Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "base/file_util.h"
7 #include <dirent.h>
8 #include <errno.h>
9 #include <fcntl.h>
10 #include <fnmatch.h>
11 #ifndef ANDROID
12 #include <fts.h>
13 #endif
14 #include <libgen.h>
15 #include <stdio.h>
16 #include <string.h>
17 #include <sys/errno.h>
18 #include <sys/mman.h>
19 #define _DARWIN_USE_64_BIT_INODE // Use 64-bit inode data structures
20 #include <sys/stat.h>
21 #include <sys/types.h>
22 #include <time.h>
23 #include <unistd.h>
25 #include <fstream>
26 #include <string>
27 #include <vector>
29 #include "base/basictypes.h"
30 #include "base/eintr_wrapper.h"
31 #include "base/file_path.h"
32 #include "base/logging.h"
33 #include "base/string_util.h"
34 #include "base/time.h"
36 namespace file_util {
38 #if defined(GOOGLE_CHROME_BUILD)
39 static const char* kTempFileName = "com.google.chrome.XXXXXX";
40 #else
41 static const char* kTempFileName = "org.chromium.XXXXXX";
42 #endif
44 bool AbsolutePath(FilePath* path) {
45 char full_path[PATH_MAX];
46 if (realpath(path->value().c_str(), full_path) == NULL)
47 return false;
48 *path = FilePath(full_path);
49 return true;
50 }
52 // TODO(erikkay): The Windows version of this accepts paths like "foo/bar/*"
53 // which works both with and without the recursive flag. I'm not sure we need
54 // that functionality. If not, remove from file_util_win.cc, otherwise add it
55 // here.
56 bool Delete(const FilePath& path, bool recursive) {
57 const char* path_str = path.value().c_str();
58 struct stat file_info;
59 int test = stat(path_str, &file_info);
60 if (test != 0) {
61 // The Windows version defines this condition as success.
62 bool ret = (errno == ENOENT || errno == ENOTDIR);
63 return ret;
64 }
65 if (!S_ISDIR(file_info.st_mode))
66 return (unlink(path_str) == 0);
67 if (!recursive)
68 return (rmdir(path_str) == 0);
70 #ifdef ANDROID
71 // XXX Need ftsless impl for bionic
72 return false;
73 #else
74 bool success = true;
75 int ftsflags = FTS_PHYSICAL | FTS_NOSTAT;
76 char top_dir[PATH_MAX];
77 if (base::strlcpy(top_dir, path_str,
78 arraysize(top_dir)) >= arraysize(top_dir)) {
79 return false;
80 }
81 char* dir_list[2] = { top_dir, NULL };
82 FTS* fts = fts_open(dir_list, ftsflags, NULL);
83 if (fts) {
84 FTSENT* fts_ent = fts_read(fts);
85 while (success && fts_ent != NULL) {
86 switch (fts_ent->fts_info) {
87 case FTS_DNR:
88 case FTS_ERR:
89 // log error
90 success = false;
91 continue;
92 break;
93 case FTS_DP:
94 success = (rmdir(fts_ent->fts_accpath) == 0);
95 break;
96 case FTS_D:
97 break;
98 case FTS_NSOK:
99 case FTS_F:
100 case FTS_SL:
101 case FTS_SLNONE:
102 success = (unlink(fts_ent->fts_accpath) == 0);
103 break;
104 default:
105 DCHECK(false);
106 break;
107 }
108 fts_ent = fts_read(fts);
109 }
110 fts_close(fts);
111 }
112 return success;
113 #endif
114 }
116 bool Move(const FilePath& from_path, const FilePath& to_path) {
117 if (rename(from_path.value().c_str(), to_path.value().c_str()) == 0)
118 return true;
120 if (!CopyDirectory(from_path, to_path, true))
121 return false;
123 Delete(from_path, true);
124 return true;
125 }
127 bool CopyDirectory(const FilePath& from_path,
128 const FilePath& to_path,
129 bool recursive) {
130 // Some old callers of CopyDirectory want it to support wildcards.
131 // After some discussion, we decided to fix those callers.
132 // Break loudly here if anyone tries to do this.
133 // TODO(evanm): remove this once we're sure it's ok.
134 DCHECK(to_path.value().find('*') == std::string::npos);
135 DCHECK(from_path.value().find('*') == std::string::npos);
137 char top_dir[PATH_MAX];
138 if (base::strlcpy(top_dir, from_path.value().c_str(),
139 arraysize(top_dir)) >= arraysize(top_dir)) {
140 return false;
141 }
143 #ifdef ANDROID
144 // XXX Need ftsless impl for bionic
145 return false;
146 #else
147 char* dir_list[] = { top_dir, NULL };
148 FTS* fts = fts_open(dir_list, FTS_PHYSICAL | FTS_NOSTAT, NULL);
149 if (!fts) {
150 CHROMIUM_LOG(ERROR) << "fts_open failed: " << strerror(errno);
151 return false;
152 }
154 int error = 0;
155 FTSENT* ent;
156 while (!error && (ent = fts_read(fts)) != NULL) {
157 // ent->fts_path is the source path, including from_path, so paste
158 // the suffix after from_path onto to_path to create the target_path.
159 std::string suffix(&ent->fts_path[from_path.value().size()]);
160 // Strip the leading '/' (if any).
161 if (!suffix.empty()) {
162 DCHECK_EQ('/', suffix[0]);
163 suffix.erase(0, 1);
164 }
165 const FilePath target_path = to_path.Append(suffix);
166 switch (ent->fts_info) {
167 case FTS_D: // Preorder directory.
168 // If we encounter a subdirectory in a non-recursive copy, prune it
169 // from the traversal.
170 if (!recursive && ent->fts_level > 0) {
171 if (fts_set(fts, ent, FTS_SKIP) != 0)
172 error = errno;
173 continue;
174 }
176 // Try creating the target dir, continuing on it if it exists already.
177 // Rely on the user's umask to produce correct permissions.
178 if (mkdir(target_path.value().c_str(), 0777) != 0) {
179 if (errno != EEXIST)
180 error = errno;
181 }
182 break;
183 case FTS_F: // Regular file.
184 case FTS_NSOK: // File, no stat info requested.
185 errno = 0;
186 if (!CopyFile(FilePath(ent->fts_path), target_path))
187 error = errno ? errno : EINVAL;
188 break;
189 case FTS_DP: // Postorder directory.
190 case FTS_DOT: // "." or ".."
191 // Skip it.
192 continue;
193 case FTS_DC: // Directory causing a cycle.
194 // Skip this branch.
195 if (fts_set(fts, ent, FTS_SKIP) != 0)
196 error = errno;
197 break;
198 case FTS_DNR: // Directory cannot be read.
199 case FTS_ERR: // Error.
200 case FTS_NS: // Stat failed.
201 // Abort with the error.
202 error = ent->fts_errno;
203 break;
204 case FTS_SL: // Symlink.
205 case FTS_SLNONE: // Symlink with broken target.
206 CHROMIUM_LOG(WARNING) << "CopyDirectory() skipping symbolic link: " <<
207 ent->fts_path;
208 continue;
209 case FTS_DEFAULT: // Some other sort of file.
210 CHROMIUM_LOG(WARNING) << "CopyDirectory() skipping file of unknown type: " <<
211 ent->fts_path;
212 continue;
213 default:
214 NOTREACHED();
215 continue; // Hope for the best!
216 }
217 }
218 // fts_read may have returned NULL and set errno to indicate an error.
219 if (!error && errno != 0)
220 error = errno;
222 if (!fts_close(fts)) {
223 // If we already have an error, let's use that error instead of the error
224 // fts_close set.
225 if (!error)
226 error = errno;
227 }
229 if (error) {
230 CHROMIUM_LOG(ERROR) << "CopyDirectory(): " << strerror(error);
231 return false;
232 }
233 return true;
234 #endif
235 }
237 bool PathExists(const FilePath& path) {
238 struct stat file_info;
239 return (stat(path.value().c_str(), &file_info) == 0);
240 }
242 bool PathIsWritable(const FilePath& path) {
243 FilePath test_path(path);
244 struct stat file_info;
245 if (stat(test_path.value().c_str(), &file_info) != 0) {
246 // If the path doesn't exist, test the parent dir.
247 test_path = test_path.DirName();
248 // If the parent dir doesn't exist, then return false (the path is not
249 // directly writable).
250 if (stat(test_path.value().c_str(), &file_info) != 0)
251 return false;
252 }
253 if (S_IWOTH & file_info.st_mode)
254 return true;
255 if (getegid() == file_info.st_gid && (S_IWGRP & file_info.st_mode))
256 return true;
257 if (geteuid() == file_info.st_uid && (S_IWUSR & file_info.st_mode))
258 return true;
259 return false;
260 }
262 bool DirectoryExists(const FilePath& path) {
263 struct stat file_info;
264 if (stat(path.value().c_str(), &file_info) == 0)
265 return S_ISDIR(file_info.st_mode);
266 return false;
267 }
269 bool ReadFromFD(int fd, char* buffer, size_t bytes) {
270 size_t total_read = 0;
271 while (total_read < bytes) {
272 ssize_t bytes_read =
273 HANDLE_EINTR(read(fd, buffer + total_read, bytes - total_read));
274 if (bytes_read <= 0)
275 break;
276 total_read += bytes_read;
277 }
278 return total_read == bytes;
279 }
281 // Creates and opens a temporary file in |directory|, returning the
282 // file descriptor. |path| is set to the temporary file path.
283 // Note TODO(erikkay) comment in header for BlahFileName() calls; the
284 // intent is to rename these files BlahFile() (since they create
285 // files, not filenames). This function does NOT unlink() the file.
286 int CreateAndOpenFdForTemporaryFile(FilePath directory, FilePath* path) {
287 *path = directory.Append(kTempFileName);
288 const std::string& tmpdir_string = path->value();
289 // this should be OK since mkstemp just replaces characters in place
290 char* buffer = const_cast<char*>(tmpdir_string.c_str());
292 return mkstemp(buffer);
293 }
295 bool CreateTemporaryFileName(FilePath* path) {
296 FilePath directory;
297 if (!GetTempDir(&directory))
298 return false;
299 int fd = CreateAndOpenFdForTemporaryFile(directory, path);
300 if (fd < 0)
301 return false;
302 close(fd);
303 return true;
304 }
306 FILE* CreateAndOpenTemporaryShmemFile(FilePath* path) {
307 FilePath directory;
308 if (!GetShmemTempDir(&directory))
309 return NULL;
311 return CreateAndOpenTemporaryFileInDir(directory, path);
312 }
314 FILE* CreateAndOpenTemporaryFileInDir(const FilePath& dir, FilePath* path) {
315 int fd = CreateAndOpenFdForTemporaryFile(dir, path);
316 if (fd < 0)
317 return NULL;
319 return fdopen(fd, "a+");
320 }
322 bool CreateTemporaryFileNameInDir(const std::wstring& dir,
323 std::wstring* temp_file) {
324 // Not implemented yet.
325 NOTREACHED();
326 return false;
327 }
329 bool CreateNewTempDirectory(const FilePath::StringType& prefix,
330 FilePath* new_temp_path) {
331 FilePath tmpdir;
332 if (!GetTempDir(&tmpdir))
333 return false;
334 tmpdir = tmpdir.Append(kTempFileName);
335 std::string tmpdir_string = tmpdir.value();
336 #ifdef ANDROID
337 char* dtemp = NULL;
338 #else
339 // this should be OK since mkdtemp just replaces characters in place
340 char* buffer = const_cast<char*>(tmpdir_string.c_str());
341 char* dtemp = mkdtemp(buffer);
342 #endif
343 if (!dtemp)
344 return false;
345 *new_temp_path = FilePath(dtemp);
346 return true;
347 }
349 bool CreateDirectory(const FilePath& full_path) {
350 std::vector<FilePath> subpaths;
352 // Collect a list of all parent directories.
353 FilePath last_path = full_path;
354 subpaths.push_back(full_path);
355 for (FilePath path = full_path.DirName();
356 path.value() != last_path.value(); path = path.DirName()) {
357 subpaths.push_back(path);
358 last_path = path;
359 }
361 // Iterate through the parents and create the missing ones.
362 for (std::vector<FilePath>::reverse_iterator i = subpaths.rbegin();
363 i != subpaths.rend(); ++i) {
364 if (!DirectoryExists(*i)) {
365 if (mkdir(i->value().c_str(), 0777) != 0)
366 return false;
367 }
368 }
369 return true;
370 }
372 bool GetFileInfo(const FilePath& file_path, FileInfo* results) {
373 struct stat file_info;
374 if (stat(file_path.value().c_str(), &file_info) != 0)
375 return false;
376 results->is_directory = S_ISDIR(file_info.st_mode);
377 results->size = file_info.st_size;
378 return true;
379 }
381 FILE* OpenFile(const std::string& filename, const char* mode) {
382 return OpenFile(FilePath(filename), mode);
383 }
385 FILE* OpenFile(const FilePath& filename, const char* mode) {
386 return fopen(filename.value().c_str(), mode);
387 }
389 int ReadFile(const FilePath& filename, char* data, int size) {
390 int fd = open(filename.value().c_str(), O_RDONLY);
391 if (fd < 0)
392 return -1;
394 int ret_value = HANDLE_EINTR(read(fd, data, size));
395 HANDLE_EINTR(close(fd));
396 return ret_value;
397 }
399 int WriteFile(const FilePath& filename, const char* data, int size) {
400 int fd = creat(filename.value().c_str(), 0666);
401 if (fd < 0)
402 return -1;
404 // Allow for partial writes
405 ssize_t bytes_written_total = 0;
406 do {
407 ssize_t bytes_written_partial =
408 HANDLE_EINTR(write(fd, data + bytes_written_total,
409 size - bytes_written_total));
410 if (bytes_written_partial < 0) {
411 HANDLE_EINTR(close(fd));
412 return -1;
413 }
414 bytes_written_total += bytes_written_partial;
415 } while (bytes_written_total < size);
417 HANDLE_EINTR(close(fd));
418 return bytes_written_total;
419 }
421 // Gets the current working directory for the process.
422 bool GetCurrentDirectory(FilePath* dir) {
423 char system_buffer[PATH_MAX] = "";
424 if (!getcwd(system_buffer, sizeof(system_buffer))) {
425 NOTREACHED();
426 return false;
427 }
428 *dir = FilePath(system_buffer);
429 return true;
430 }
432 // Sets the current working directory for the process.
433 bool SetCurrentDirectory(const FilePath& path) {
434 int ret = chdir(path.value().c_str());
435 return !ret;
436 }
438 #if !defined(OS_MACOSX)
439 bool GetTempDir(FilePath* path) {
440 const char* tmp = getenv("TMPDIR");
441 if (tmp)
442 *path = FilePath(tmp);
443 else
444 *path = FilePath("/tmp");
445 return true;
446 }
448 bool GetShmemTempDir(FilePath* path) {
449 #if defined(OS_LINUX) && !defined(ANDROID)
450 *path = FilePath("/dev/shm");
451 return true;
452 #else
453 return GetTempDir(path);
454 #endif
455 }
457 bool CopyFile(const FilePath& from_path, const FilePath& to_path) {
458 int infile = open(from_path.value().c_str(), O_RDONLY);
459 if (infile < 0)
460 return false;
462 int outfile = creat(to_path.value().c_str(), 0666);
463 if (outfile < 0) {
464 close(infile);
465 return false;
466 }
468 const size_t kBufferSize = 32768;
469 std::vector<char> buffer(kBufferSize);
470 bool result = true;
472 while (result) {
473 ssize_t bytes_read = HANDLE_EINTR(read(infile, &buffer[0], buffer.size()));
474 if (bytes_read < 0) {
475 result = false;
476 break;
477 }
478 if (bytes_read == 0)
479 break;
480 // Allow for partial writes
481 ssize_t bytes_written_per_read = 0;
482 do {
483 ssize_t bytes_written_partial = HANDLE_EINTR(write(
484 outfile,
485 &buffer[bytes_written_per_read],
486 bytes_read - bytes_written_per_read));
487 if (bytes_written_partial < 0) {
488 result = false;
489 break;
490 }
491 bytes_written_per_read += bytes_written_partial;
492 } while (bytes_written_per_read < bytes_read);
493 }
495 if (HANDLE_EINTR(close(infile)) < 0)
496 result = false;
497 if (HANDLE_EINTR(close(outfile)) < 0)
498 result = false;
500 return result;
501 }
502 #endif // !defined(OS_MACOSX)
504 } // namespace file_util