Home | History | Annotate | Download | only in base
      1 // Copyright (c) 2011 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.
      4 
      5 #include "base/file_util.h"
      6 
      7 #include <dirent.h>
      8 #include <errno.h>
      9 #include <fcntl.h>
     10 #include <fnmatch.h>
     11 #include <libgen.h>
     12 #include <limits.h>
     13 #include <stdio.h>
     14 #include <stdlib.h>
     15 #include <string.h>
     16 #include <sys/errno.h>
     17 #include <sys/mman.h>
     18 #include <sys/param.h>
     19 #include <sys/stat.h>
     20 #include <sys/time.h>
     21 #include <sys/types.h>
     22 #include <time.h>
     23 #include <unistd.h>
     24 
     25 #if defined(OS_MACOSX)
     26 #include <AvailabilityMacros.h>
     27 #elif !defined(ANDROID)
     28 #include <glib.h>
     29 #endif
     30 
     31 #include <fstream>
     32 
     33 #include "base/basictypes.h"
     34 #include "base/eintr_wrapper.h"
     35 #include "base/file_path.h"
     36 #include "base/logging.h"
     37 #include "base/memory/scoped_ptr.h"
     38 #include "base/memory/singleton.h"
     39 #include "base/string_util.h"
     40 #include "base/sys_string_conversions.h"
     41 #include "base/threading/thread_restrictions.h"
     42 #include "base/time.h"
     43 #include "base/utf_string_conversions.h"
     44 
     45 namespace file_util {
     46 
     47 namespace {
     48 
     49 // Helper for NormalizeFilePath(), defined below.
     50 bool RealPath(const FilePath& path, FilePath* real_path) {
     51   base::ThreadRestrictions::AssertIOAllowed();  // For realpath().
     52   FilePath::CharType buf[PATH_MAX];
     53   if (!realpath(path.value().c_str(), buf))
     54     return false;
     55 
     56   *real_path = FilePath(buf);
     57   return true;
     58 }
     59 
     60 }  // namespace
     61 
     62 #if defined(OS_OPENBSD) || defined(OS_FREEBSD) || \
     63     (defined(OS_MACOSX) && \
     64      MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5)
     65 typedef struct stat stat_wrapper_t;
     66 static int CallStat(const char *path, stat_wrapper_t *sb) {
     67   base::ThreadRestrictions::AssertIOAllowed();
     68   return stat(path, sb);
     69 }
     70 #else
     71 typedef struct stat64 stat_wrapper_t;
     72 static int CallStat(const char *path, stat_wrapper_t *sb) {
     73   base::ThreadRestrictions::AssertIOAllowed();
     74   return stat64(path, sb);
     75 }
     76 #endif
     77 
     78 
     79 #if defined(GOOGLE_CHROME_BUILD)
     80 static const char* kTempFileName = ".com.google.chrome.XXXXXX";
     81 #else
     82 static const char* kTempFileName = ".org.chromium.XXXXXX";
     83 #endif
     84 
     85 bool AbsolutePath(FilePath* path) {
     86   base::ThreadRestrictions::AssertIOAllowed();  // For realpath().
     87   char full_path[PATH_MAX];
     88   if (realpath(path->value().c_str(), full_path) == NULL)
     89     return false;
     90   *path = FilePath(full_path);
     91   return true;
     92 }
     93 
     94 int CountFilesCreatedAfter(const FilePath& path,
     95                            const base::Time& comparison_time) {
     96   base::ThreadRestrictions::AssertIOAllowed();
     97   int file_count = 0;
     98 
     99   DIR* dir = opendir(path.value().c_str());
    100   if (dir) {
    101 #if !defined(OS_LINUX) && !defined(OS_MACOSX) && !defined(OS_FREEBSD) && \
    102     !defined(OS_OPENBSD) && !defined(OS_SOLARIS)
    103   #error Port warning: depending on the definition of struct dirent, \
    104          additional space for pathname may be needed
    105 #endif
    106     struct dirent ent_buf;
    107     struct dirent* ent;
    108     while (readdir_r(dir, &ent_buf, &ent) == 0 && ent) {
    109       if ((strcmp(ent->d_name, ".") == 0) ||
    110           (strcmp(ent->d_name, "..") == 0))
    111         continue;
    112 
    113       stat_wrapper_t st;
    114       int test = CallStat(path.Append(ent->d_name).value().c_str(), &st);
    115       if (test != 0) {
    116         PLOG(ERROR) << "stat64 failed";
    117         continue;
    118       }
    119       // Here, we use Time::TimeT(), which discards microseconds. This
    120       // means that files which are newer than |comparison_time| may
    121       // be considered older. If we don't discard microseconds, it
    122       // introduces another issue. Suppose the following case:
    123       //
    124       // 1. Get |comparison_time| by Time::Now() and the value is 10.1 (secs).
    125       // 2. Create a file and the current time is 10.3 (secs).
    126       //
    127       // As POSIX doesn't have microsecond precision for |st_ctime|,
    128       // the creation time of the file created in the step 2 is 10 and
    129       // the file is considered older than |comparison_time|. After
    130       // all, we may have to accept either of the two issues: 1. files
    131       // which are older than |comparison_time| are considered newer
    132       // (current implementation) 2. files newer than
    133       // |comparison_time| are considered older.
    134       if (static_cast<time_t>(st.st_ctime) >= comparison_time.ToTimeT())
    135         ++file_count;
    136     }
    137     closedir(dir);
    138   }
    139   return file_count;
    140 }
    141 
    142 // TODO(erikkay): The Windows version of this accepts paths like "foo/bar/*"
    143 // which works both with and without the recursive flag.  I'm not sure we need
    144 // that functionality. If not, remove from file_util_win.cc, otherwise add it
    145 // here.
    146 bool Delete(const FilePath& path, bool recursive) {
    147   base::ThreadRestrictions::AssertIOAllowed();
    148   const char* path_str = path.value().c_str();
    149   stat_wrapper_t file_info;
    150   int test = CallStat(path_str, &file_info);
    151   if (test != 0) {
    152     // The Windows version defines this condition as success.
    153     bool ret = (errno == ENOENT || errno == ENOTDIR);
    154     return ret;
    155   }
    156   if (!S_ISDIR(file_info.st_mode))
    157     return (unlink(path_str) == 0);
    158   if (!recursive)
    159     return (rmdir(path_str) == 0);
    160 
    161   bool success = true;
    162   std::stack<std::string> directories;
    163   directories.push(path.value());
    164   FileEnumerator traversal(path, true, static_cast<FileEnumerator::FILE_TYPE>(
    165         FileEnumerator::FILES | FileEnumerator::DIRECTORIES |
    166         FileEnumerator::SHOW_SYM_LINKS));
    167   for (FilePath current = traversal.Next(); success && !current.empty();
    168        current = traversal.Next()) {
    169     FileEnumerator::FindInfo info;
    170     traversal.GetFindInfo(&info);
    171 
    172     if (S_ISDIR(info.stat.st_mode))
    173       directories.push(current.value());
    174     else
    175       success = (unlink(current.value().c_str()) == 0);
    176   }
    177 
    178   while (success && !directories.empty()) {
    179     FilePath dir = FilePath(directories.top());
    180     directories.pop();
    181     success = (rmdir(dir.value().c_str()) == 0);
    182   }
    183   return success;
    184 }
    185 
    186 bool Move(const FilePath& from_path, const FilePath& to_path) {
    187   base::ThreadRestrictions::AssertIOAllowed();
    188   // Windows compatibility: if to_path exists, from_path and to_path
    189   // must be the same type, either both files, or both directories.
    190   stat_wrapper_t to_file_info;
    191   if (CallStat(to_path.value().c_str(), &to_file_info) == 0) {
    192     stat_wrapper_t from_file_info;
    193     if (CallStat(from_path.value().c_str(), &from_file_info) == 0) {
    194       if (S_ISDIR(to_file_info.st_mode) != S_ISDIR(from_file_info.st_mode))
    195         return false;
    196     } else {
    197       return false;
    198     }
    199   }
    200 
    201   if (rename(from_path.value().c_str(), to_path.value().c_str()) == 0)
    202     return true;
    203 
    204   if (!CopyDirectory(from_path, to_path, true))
    205     return false;
    206 
    207   Delete(from_path, true);
    208   return true;
    209 }
    210 
    211 bool ReplaceFile(const FilePath& from_path, const FilePath& to_path) {
    212   base::ThreadRestrictions::AssertIOAllowed();
    213   return (rename(from_path.value().c_str(), to_path.value().c_str()) == 0);
    214 }
    215 
    216 bool CopyDirectory(const FilePath& from_path,
    217                    const FilePath& to_path,
    218                    bool recursive) {
    219   base::ThreadRestrictions::AssertIOAllowed();
    220   // Some old callers of CopyDirectory want it to support wildcards.
    221   // After some discussion, we decided to fix those callers.
    222   // Break loudly here if anyone tries to do this.
    223   // TODO(evanm): remove this once we're sure it's ok.
    224   DCHECK(to_path.value().find('*') == std::string::npos);
    225   DCHECK(from_path.value().find('*') == std::string::npos);
    226 
    227   char top_dir[PATH_MAX];
    228   if (base::strlcpy(top_dir, from_path.value().c_str(),
    229                     arraysize(top_dir)) >= arraysize(top_dir)) {
    230     return false;
    231   }
    232 
    233   // This function does not properly handle destinations within the source
    234   FilePath real_to_path = to_path;
    235   if (PathExists(real_to_path)) {
    236     if (!AbsolutePath(&real_to_path))
    237       return false;
    238   } else {
    239     real_to_path = real_to_path.DirName();
    240     if (!AbsolutePath(&real_to_path))
    241       return false;
    242   }
    243   FilePath real_from_path = from_path;
    244   if (!AbsolutePath(&real_from_path))
    245     return false;
    246   if (real_to_path.value().size() >= real_from_path.value().size() &&
    247       real_to_path.value().compare(0, real_from_path.value().size(),
    248       real_from_path.value()) == 0)
    249     return false;
    250 
    251   bool success = true;
    252   FileEnumerator::FILE_TYPE traverse_type =
    253       static_cast<FileEnumerator::FILE_TYPE>(FileEnumerator::FILES |
    254       FileEnumerator::SHOW_SYM_LINKS);
    255   if (recursive)
    256     traverse_type = static_cast<FileEnumerator::FILE_TYPE>(
    257         traverse_type | FileEnumerator::DIRECTORIES);
    258   FileEnumerator traversal(from_path, recursive, traverse_type);
    259 
    260   // We have to mimic windows behavior here. |to_path| may not exist yet,
    261   // start the loop with |to_path|.
    262   FileEnumerator::FindInfo info;
    263   FilePath current = from_path;
    264   if (stat(from_path.value().c_str(), &info.stat) < 0) {
    265     LOG(ERROR) << "CopyDirectory() couldn't stat source directory: " <<
    266         from_path.value() << " errno = " << errno;
    267     success = false;
    268   }
    269   struct stat to_path_stat;
    270   FilePath from_path_base = from_path;
    271   if (recursive && stat(to_path.value().c_str(), &to_path_stat) == 0 &&
    272       S_ISDIR(to_path_stat.st_mode)) {
    273     // If the destination already exists and is a directory, then the
    274     // top level of source needs to be copied.
    275     from_path_base = from_path.DirName();
    276   }
    277 
    278   // The Windows version of this function assumes that non-recursive calls
    279   // will always have a directory for from_path.
    280   DCHECK(recursive || S_ISDIR(info.stat.st_mode));
    281 
    282   while (success && !current.empty()) {
    283     // current is the source path, including from_path, so paste
    284     // the suffix after from_path onto to_path to create the target_path.
    285     std::string suffix(&current.value().c_str()[from_path_base.value().size()]);
    286     // Strip the leading '/' (if any).
    287     if (!suffix.empty()) {
    288       DCHECK_EQ('/', suffix[0]);
    289       suffix.erase(0, 1);
    290     }
    291     const FilePath target_path = to_path.Append(suffix);
    292 
    293     if (S_ISDIR(info.stat.st_mode)) {
    294       if (mkdir(target_path.value().c_str(), info.stat.st_mode & 01777) != 0 &&
    295           errno != EEXIST) {
    296         LOG(ERROR) << "CopyDirectory() couldn't create directory: " <<
    297             target_path.value() << " errno = " << errno;
    298         success = false;
    299       }
    300     } else if (S_ISREG(info.stat.st_mode)) {
    301       if (!CopyFile(current, target_path)) {
    302         LOG(ERROR) << "CopyDirectory() couldn't create file: " <<
    303             target_path.value();
    304         success = false;
    305       }
    306     } else {
    307       LOG(WARNING) << "CopyDirectory() skipping non-regular file: " <<
    308           current.value();
    309     }
    310 
    311     current = traversal.Next();
    312     traversal.GetFindInfo(&info);
    313   }
    314 
    315   return success;
    316 }
    317 
    318 bool PathExists(const FilePath& path) {
    319   base::ThreadRestrictions::AssertIOAllowed();
    320   return access(path.value().c_str(), F_OK) == 0;
    321 }
    322 
    323 bool PathIsWritable(const FilePath& path) {
    324   base::ThreadRestrictions::AssertIOAllowed();
    325   return access(path.value().c_str(), W_OK) == 0;
    326 }
    327 
    328 bool DirectoryExists(const FilePath& path) {
    329   base::ThreadRestrictions::AssertIOAllowed();
    330   stat_wrapper_t file_info;
    331   if (CallStat(path.value().c_str(), &file_info) == 0)
    332     return S_ISDIR(file_info.st_mode);
    333   return false;
    334 }
    335 
    336 // TODO(erikkay): implement
    337 #if 0
    338 bool GetFileCreationLocalTimeFromHandle(int fd,
    339                                         LPSYSTEMTIME creation_time) {
    340   if (!file_handle)
    341     return false;
    342 
    343   FILETIME utc_filetime;
    344   if (!GetFileTime(file_handle, &utc_filetime, NULL, NULL))
    345     return false;
    346 
    347   FILETIME local_filetime;
    348   if (!FileTimeToLocalFileTime(&utc_filetime, &local_filetime))
    349     return false;
    350 
    351   return !!FileTimeToSystemTime(&local_filetime, creation_time);
    352 }
    353 
    354 bool GetFileCreationLocalTime(const std::string& filename,
    355                               LPSYSTEMTIME creation_time) {
    356   ScopedHandle file_handle(
    357       CreateFile(filename.c_str(), GENERIC_READ,
    358                  FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL,
    359                  OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL));
    360   return GetFileCreationLocalTimeFromHandle(file_handle.Get(), creation_time);
    361 }
    362 #endif
    363 
    364 bool ReadFromFD(int fd, char* buffer, size_t bytes) {
    365   size_t total_read = 0;
    366   while (total_read < bytes) {
    367     ssize_t bytes_read =
    368         HANDLE_EINTR(read(fd, buffer + total_read, bytes - total_read));
    369     if (bytes_read <= 0)
    370       break;
    371     total_read += bytes_read;
    372   }
    373   return total_read == bytes;
    374 }
    375 
    376 bool CreateSymbolicLink(const FilePath& target_path,
    377                         const FilePath& symlink_path) {
    378   DCHECK(!symlink_path.empty());
    379   DCHECK(!target_path.empty());
    380   return ::symlink(target_path.value().c_str(),
    381                    symlink_path.value().c_str()) != -1;
    382 }
    383 
    384 bool ReadSymbolicLink(const FilePath& symlink_path,
    385                       FilePath* target_path) {
    386   DCHECK(!symlink_path.empty());
    387   DCHECK(target_path);
    388   char buf[PATH_MAX];
    389   ssize_t count = ::readlink(symlink_path.value().c_str(), buf, arraysize(buf));
    390 
    391   if (count <= 0) {
    392     target_path->clear();
    393     return false;
    394   }
    395 
    396   *target_path = FilePath(FilePath::StringType(buf, count));
    397   return true;
    398 }
    399 
    400 // Creates and opens a temporary file in |directory|, returning the
    401 // file descriptor. |path| is set to the temporary file path.
    402 // This function does NOT unlink() the file.
    403 int CreateAndOpenFdForTemporaryFile(FilePath directory, FilePath* path) {
    404   base::ThreadRestrictions::AssertIOAllowed();  // For call to mkstemp().
    405   *path = directory.Append(kTempFileName);
    406   const std::string& tmpdir_string = path->value();
    407   // this should be OK since mkstemp just replaces characters in place
    408   char* buffer = const_cast<char*>(tmpdir_string.c_str());
    409 
    410   return HANDLE_EINTR(mkstemp(buffer));
    411 }
    412 
    413 bool CreateTemporaryFile(FilePath* path) {
    414   base::ThreadRestrictions::AssertIOAllowed();  // For call to close().
    415   FilePath directory;
    416   if (!GetTempDir(&directory))
    417     return false;
    418   int fd = CreateAndOpenFdForTemporaryFile(directory, path);
    419   if (fd < 0)
    420     return false;
    421   ignore_result(HANDLE_EINTR(close(fd)));
    422   return true;
    423 }
    424 
    425 FILE* CreateAndOpenTemporaryShmemFile(FilePath* path) {
    426   FilePath directory;
    427   if (!GetShmemTempDir(&directory))
    428     return NULL;
    429 
    430   return CreateAndOpenTemporaryFileInDir(directory, path);
    431 }
    432 
    433 FILE* CreateAndOpenTemporaryFileInDir(const FilePath& dir, FilePath* path) {
    434   int fd = CreateAndOpenFdForTemporaryFile(dir, path);
    435   if (fd < 0)
    436     return NULL;
    437 
    438   FILE* file = fdopen(fd, "a+");
    439   if (!file)
    440     ignore_result(HANDLE_EINTR(close(fd)));
    441   return file;
    442 }
    443 
    444 bool CreateTemporaryFileInDir(const FilePath& dir, FilePath* temp_file) {
    445   base::ThreadRestrictions::AssertIOAllowed();  // For call to close().
    446   int fd = CreateAndOpenFdForTemporaryFile(dir, temp_file);
    447   return ((fd >= 0) && !HANDLE_EINTR(close(fd)));
    448 }
    449 
    450 static bool CreateTemporaryDirInDirImpl(const FilePath& base_dir,
    451                                         const FilePath::StringType& name_tmpl,
    452                                         FilePath* new_dir) {
    453   base::ThreadRestrictions::AssertIOAllowed();  // For call to mkdtemp().
    454   CHECK(name_tmpl.find("XXXXXX") != FilePath::StringType::npos)
    455     << "Directory name template must contain \"XXXXXX\".";
    456 
    457   FilePath sub_dir = base_dir.Append(name_tmpl);
    458   std::string sub_dir_string = sub_dir.value();
    459 
    460   // this should be OK since mkdtemp just replaces characters in place
    461   char* buffer = const_cast<char*>(sub_dir_string.c_str());
    462   char* dtemp = mkdtemp(buffer);
    463   if (!dtemp) {
    464     DPLOG(ERROR) << "mkdtemp";
    465     return false;
    466   }
    467   *new_dir = FilePath(dtemp);
    468   return true;
    469 }
    470 
    471 bool CreateTemporaryDirInDir(const FilePath& base_dir,
    472                              const FilePath::StringType& prefix,
    473                              FilePath* new_dir) {
    474   FilePath::StringType mkdtemp_template = prefix;
    475   mkdtemp_template.append(FILE_PATH_LITERAL("XXXXXX"));
    476   return CreateTemporaryDirInDirImpl(base_dir, mkdtemp_template, new_dir);
    477 }
    478 
    479 bool CreateNewTempDirectory(const FilePath::StringType& prefix,
    480                             FilePath* new_temp_path) {
    481   FilePath tmpdir;
    482   if (!GetTempDir(&tmpdir))
    483     return false;
    484 
    485   return CreateTemporaryDirInDirImpl(tmpdir, kTempFileName, new_temp_path);
    486 }
    487 
    488 bool CreateDirectory(const FilePath& full_path) {
    489   base::ThreadRestrictions::AssertIOAllowed();  // For call to mkdir().
    490   std::vector<FilePath> subpaths;
    491 
    492   // Collect a list of all parent directories.
    493   FilePath last_path = full_path;
    494   subpaths.push_back(full_path);
    495   for (FilePath path = full_path.DirName();
    496        path.value() != last_path.value(); path = path.DirName()) {
    497     subpaths.push_back(path);
    498     last_path = path;
    499   }
    500 
    501   // Iterate through the parents and create the missing ones.
    502   for (std::vector<FilePath>::reverse_iterator i = subpaths.rbegin();
    503        i != subpaths.rend(); ++i) {
    504     if (DirectoryExists(*i))
    505       continue;
    506     if (mkdir(i->value().c_str(), 0700) == 0)
    507       continue;
    508     // Mkdir failed, but it might have failed with EEXIST, or some other error
    509     // due to the the directory appearing out of thin air. This can occur if
    510     // two processes are trying to create the same file system tree at the same
    511     // time. Check to see if it exists and make sure it is a directory.
    512     if (!DirectoryExists(*i))
    513       return false;
    514   }
    515   return true;
    516 }
    517 
    518 bool GetFileInfo(const FilePath& file_path, base::PlatformFileInfo* results) {
    519   stat_wrapper_t file_info;
    520   if (CallStat(file_path.value().c_str(), &file_info) != 0)
    521     return false;
    522   results->is_directory = S_ISDIR(file_info.st_mode);
    523   results->size = file_info.st_size;
    524   results->last_modified = base::Time::FromTimeT(file_info.st_mtime);
    525   results->last_accessed = base::Time::FromTimeT(file_info.st_atime);
    526   results->creation_time = base::Time::FromTimeT(file_info.st_ctime);
    527   return true;
    528 }
    529 
    530 bool GetInode(const FilePath& path, ino_t* inode) {
    531   base::ThreadRestrictions::AssertIOAllowed();  // For call to stat().
    532   struct stat buffer;
    533   int result = stat(path.value().c_str(), &buffer);
    534   if (result < 0)
    535     return false;
    536 
    537   *inode = buffer.st_ino;
    538   return true;
    539 }
    540 
    541 FILE* OpenFile(const std::string& filename, const char* mode) {
    542   return OpenFile(FilePath(filename), mode);
    543 }
    544 
    545 FILE* OpenFile(const FilePath& filename, const char* mode) {
    546   base::ThreadRestrictions::AssertIOAllowed();
    547   FILE* result = NULL;
    548   do {
    549     result = fopen(filename.value().c_str(), mode);
    550   } while (!result && errno == EINTR);
    551   return result;
    552 }
    553 
    554 int ReadFile(const FilePath& filename, char* data, int size) {
    555   base::ThreadRestrictions::AssertIOAllowed();
    556   int fd = HANDLE_EINTR(open(filename.value().c_str(), O_RDONLY));
    557   if (fd < 0)
    558     return -1;
    559 
    560   ssize_t bytes_read = HANDLE_EINTR(read(fd, data, size));
    561   if (int ret = HANDLE_EINTR(close(fd)) < 0)
    562     return ret;
    563   return bytes_read;
    564 }
    565 
    566 int WriteFile(const FilePath& filename, const char* data, int size) {
    567   base::ThreadRestrictions::AssertIOAllowed();
    568   int fd = HANDLE_EINTR(creat(filename.value().c_str(), 0666));
    569   if (fd < 0)
    570     return -1;
    571 
    572   int bytes_written = WriteFileDescriptor(fd, data, size);
    573   if (int ret = HANDLE_EINTR(close(fd)) < 0)
    574     return ret;
    575   return bytes_written;
    576 }
    577 
    578 int WriteFileDescriptor(const int fd, const char* data, int size) {
    579   // Allow for partial writes.
    580   ssize_t bytes_written_total = 0;
    581   for (ssize_t bytes_written_partial = 0; bytes_written_total < size;
    582        bytes_written_total += bytes_written_partial) {
    583     bytes_written_partial =
    584         HANDLE_EINTR(write(fd, data + bytes_written_total,
    585                            size - bytes_written_total));
    586     if (bytes_written_partial < 0)
    587       return -1;
    588   }
    589 
    590   return bytes_written_total;
    591 }
    592 
    593 // Gets the current working directory for the process.
    594 bool GetCurrentDirectory(FilePath* dir) {
    595   // getcwd can return ENOENT, which implies it checks against the disk.
    596   base::ThreadRestrictions::AssertIOAllowed();
    597 
    598   char system_buffer[PATH_MAX] = "";
    599   if (!getcwd(system_buffer, sizeof(system_buffer))) {
    600     NOTREACHED();
    601     return false;
    602   }
    603   *dir = FilePath(system_buffer);
    604   return true;
    605 }
    606 
    607 // Sets the current working directory for the process.
    608 bool SetCurrentDirectory(const FilePath& path) {
    609   base::ThreadRestrictions::AssertIOAllowed();
    610   int ret = chdir(path.value().c_str());
    611   return !ret;
    612 }
    613 
    614 ///////////////////////////////////////////////
    615 // FileEnumerator
    616 
    617 FileEnumerator::FileEnumerator(const FilePath& root_path,
    618                                bool recursive,
    619                                FileEnumerator::FILE_TYPE file_type)
    620     : current_directory_entry_(0),
    621       root_path_(root_path),
    622       recursive_(recursive),
    623       file_type_(file_type) {
    624   // INCLUDE_DOT_DOT must not be specified if recursive.
    625   DCHECK(!(recursive && (INCLUDE_DOT_DOT & file_type_)));
    626   pending_paths_.push(root_path);
    627 }
    628 
    629 FileEnumerator::FileEnumerator(const FilePath& root_path,
    630                                bool recursive,
    631                                FileEnumerator::FILE_TYPE file_type,
    632                                const FilePath::StringType& pattern)
    633     : current_directory_entry_(0),
    634       root_path_(root_path),
    635       recursive_(recursive),
    636       file_type_(file_type),
    637       pattern_(root_path.Append(pattern).value()) {
    638   // INCLUDE_DOT_DOT must not be specified if recursive.
    639   DCHECK(!(recursive && (INCLUDE_DOT_DOT & file_type_)));
    640   // The Windows version of this code appends the pattern to the root_path,
    641   // potentially only matching against items in the top-most directory.
    642   // Do the same here.
    643   if (pattern.empty())
    644     pattern_ = FilePath::StringType();
    645   pending_paths_.push(root_path);
    646 }
    647 
    648 FileEnumerator::~FileEnumerator() {
    649 }
    650 
    651 FilePath FileEnumerator::Next() {
    652   ++current_directory_entry_;
    653 
    654   // While we've exhausted the entries in the current directory, do the next
    655   while (current_directory_entry_ >= directory_entries_.size()) {
    656     if (pending_paths_.empty())
    657       return FilePath();
    658 
    659     root_path_ = pending_paths_.top();
    660     root_path_ = root_path_.StripTrailingSeparators();
    661     pending_paths_.pop();
    662 
    663     std::vector<DirectoryEntryInfo> entries;
    664     if (!ReadDirectory(&entries, root_path_, file_type_ & SHOW_SYM_LINKS))
    665       continue;
    666 
    667     directory_entries_.clear();
    668     current_directory_entry_ = 0;
    669     for (std::vector<DirectoryEntryInfo>::const_iterator
    670         i = entries.begin(); i != entries.end(); ++i) {
    671       FilePath full_path = root_path_.Append(i->filename);
    672       if (ShouldSkip(full_path))
    673         continue;
    674 
    675       if (pattern_.size() &&
    676           fnmatch(pattern_.c_str(), full_path.value().c_str(), FNM_NOESCAPE))
    677         continue;
    678 
    679       if (recursive_ && S_ISDIR(i->stat.st_mode))
    680         pending_paths_.push(full_path);
    681 
    682       if ((S_ISDIR(i->stat.st_mode) && (file_type_ & DIRECTORIES)) ||
    683           (!S_ISDIR(i->stat.st_mode) && (file_type_ & FILES)))
    684         directory_entries_.push_back(*i);
    685     }
    686   }
    687 
    688   return root_path_.Append(directory_entries_[current_directory_entry_
    689       ].filename);
    690 }
    691 
    692 void FileEnumerator::GetFindInfo(FindInfo* info) {
    693   DCHECK(info);
    694 
    695   if (current_directory_entry_ >= directory_entries_.size())
    696     return;
    697 
    698   DirectoryEntryInfo* cur_entry = &directory_entries_[current_directory_entry_];
    699   memcpy(&(info->stat), &(cur_entry->stat), sizeof(info->stat));
    700   info->filename.assign(cur_entry->filename.value());
    701 }
    702 
    703 bool FileEnumerator::IsDirectory(const FindInfo& info) {
    704   return S_ISDIR(info.stat.st_mode);
    705 }
    706 
    707 // static
    708 FilePath FileEnumerator::GetFilename(const FindInfo& find_info) {
    709   return FilePath(find_info.filename);
    710 }
    711 
    712 bool FileEnumerator::ReadDirectory(std::vector<DirectoryEntryInfo>* entries,
    713                                    const FilePath& source, bool show_links) {
    714   base::ThreadRestrictions::AssertIOAllowed();
    715   DIR* dir = opendir(source.value().c_str());
    716   if (!dir)
    717     return false;
    718 
    719 #if !defined(OS_LINUX) && !defined(OS_MACOSX) && !defined(OS_FREEBSD) && \
    720     !defined(OS_OPENBSD) && !defined(OS_SOLARIS)
    721   #error Port warning: depending on the definition of struct dirent, \
    722          additional space for pathname may be needed
    723 #endif
    724 
    725   struct dirent dent_buf;
    726   struct dirent* dent;
    727   while (readdir_r(dir, &dent_buf, &dent) == 0 && dent) {
    728     DirectoryEntryInfo info;
    729     info.filename = FilePath(dent->d_name);
    730 
    731     FilePath full_name = source.Append(dent->d_name);
    732     int ret;
    733     if (show_links)
    734       ret = lstat(full_name.value().c_str(), &info.stat);
    735     else
    736       ret = stat(full_name.value().c_str(), &info.stat);
    737     if (ret < 0) {
    738       // Print the stat() error message unless it was ENOENT and we're
    739       // following symlinks.
    740       if (!(errno == ENOENT && !show_links)) {
    741         PLOG(ERROR) << "Couldn't stat "
    742                     << source.Append(dent->d_name).value();
    743       }
    744       memset(&info.stat, 0, sizeof(info.stat));
    745     }
    746     entries->push_back(info);
    747   }
    748 
    749   closedir(dir);
    750   return true;
    751 }
    752 
    753 ///////////////////////////////////////////////
    754 // MemoryMappedFile
    755 
    756 MemoryMappedFile::MemoryMappedFile()
    757     : file_(base::kInvalidPlatformFileValue),
    758       data_(NULL),
    759       length_(0) {
    760 }
    761 
    762 bool MemoryMappedFile::MapFileToMemoryInternal() {
    763   base::ThreadRestrictions::AssertIOAllowed();
    764 
    765   struct stat file_stat;
    766   if (fstat(file_, &file_stat) == base::kInvalidPlatformFileValue) {
    767     LOG(ERROR) << "Couldn't fstat " << file_ << ", errno " << errno;
    768     return false;
    769   }
    770   length_ = file_stat.st_size;
    771 
    772   data_ = static_cast<uint8*>(
    773       mmap(NULL, length_, PROT_READ, MAP_SHARED, file_, 0));
    774   if (data_ == MAP_FAILED)
    775     LOG(ERROR) << "Couldn't mmap " << file_ << ", errno " << errno;
    776 
    777   return data_ != MAP_FAILED;
    778 }
    779 
    780 void MemoryMappedFile::CloseHandles() {
    781   base::ThreadRestrictions::AssertIOAllowed();
    782 
    783   if (data_ != NULL)
    784     munmap(data_, length_);
    785   if (file_ != base::kInvalidPlatformFileValue)
    786     ignore_result(HANDLE_EINTR(close(file_)));
    787 
    788   data_ = NULL;
    789   length_ = 0;
    790   file_ = base::kInvalidPlatformFileValue;
    791 }
    792 
    793 bool HasFileBeenModifiedSince(const FileEnumerator::FindInfo& find_info,
    794                               const base::Time& cutoff_time) {
    795   return static_cast<time_t>(find_info.stat.st_mtime) >= cutoff_time.ToTimeT();
    796 }
    797 
    798 bool NormalizeFilePath(const FilePath& path, FilePath* normalized_path) {
    799   FilePath real_path_result;
    800   if (!RealPath(path, &real_path_result))
    801     return false;
    802 
    803   // To be consistant with windows, fail if |real_path_result| is a
    804   // directory.
    805   stat_wrapper_t file_info;
    806   if (CallStat(real_path_result.value().c_str(), &file_info) != 0 ||
    807       S_ISDIR(file_info.st_mode))
    808     return false;
    809 
    810   *normalized_path = real_path_result;
    811   return true;
    812 }
    813 
    814 #if !defined(OS_MACOSX)
    815 bool GetTempDir(FilePath* path) {
    816   const char* tmp = getenv("TMPDIR");
    817   if (tmp)
    818     *path = FilePath(tmp);
    819   else
    820     *path = FilePath("/tmp");
    821   return true;
    822 }
    823 
    824 bool GetShmemTempDir(FilePath* path) {
    825   *path = FilePath("/dev/shm");
    826   return true;
    827 }
    828 
    829 FilePath GetHomeDir() {
    830 #ifndef ANDROID
    831   const char* home_dir = getenv("HOME");
    832   if (home_dir && home_dir[0])
    833     return FilePath(home_dir);
    834 
    835   // g_get_home_dir calls getpwent, which can fall through to LDAP calls.
    836   base::ThreadRestrictions::AssertIOAllowed();
    837 
    838   home_dir = g_get_home_dir();
    839   if (home_dir && home_dir[0])
    840     return FilePath(home_dir);
    841 
    842   FilePath rv;
    843   if (file_util::GetTempDir(&rv))
    844     return rv;
    845 #endif
    846   // Last resort.
    847   return FilePath("/tmp");
    848 }
    849 
    850 bool CopyFile(const FilePath& from_path, const FilePath& to_path) {
    851   base::ThreadRestrictions::AssertIOAllowed();
    852   int infile = HANDLE_EINTR(open(from_path.value().c_str(), O_RDONLY));
    853   if (infile < 0)
    854     return false;
    855 
    856   int outfile = HANDLE_EINTR(creat(to_path.value().c_str(), 0666));
    857   if (outfile < 0) {
    858     ignore_result(HANDLE_EINTR(close(infile)));
    859     return false;
    860   }
    861 
    862   const size_t kBufferSize = 32768;
    863   std::vector<char> buffer(kBufferSize);
    864   bool result = true;
    865 
    866   while (result) {
    867     ssize_t bytes_read = HANDLE_EINTR(read(infile, &buffer[0], buffer.size()));
    868     if (bytes_read < 0) {
    869       result = false;
    870       break;
    871     }
    872     if (bytes_read == 0)
    873       break;
    874     // Allow for partial writes
    875     ssize_t bytes_written_per_read = 0;
    876     do {
    877       ssize_t bytes_written_partial = HANDLE_EINTR(write(
    878           outfile,
    879           &buffer[bytes_written_per_read],
    880           bytes_read - bytes_written_per_read));
    881       if (bytes_written_partial < 0) {
    882         result = false;
    883         break;
    884       }
    885       bytes_written_per_read += bytes_written_partial;
    886     } while (bytes_written_per_read < bytes_read);
    887   }
    888 
    889   if (HANDLE_EINTR(close(infile)) < 0)
    890     result = false;
    891   if (HANDLE_EINTR(close(outfile)) < 0)
    892     result = false;
    893 
    894   return result;
    895 }
    896 #endif  // defined(OS_MACOSX)
    897 
    898 }  // namespace file_util
    899