ipc/chromium/src/base/file_util_posix.cc

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

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

mercurial