Home | History | Annotate | Download | only in base
      1 // Copyright (c) 2012 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 <libgen.h>
     11 #include <limits.h>
     12 #include <stdio.h>
     13 #include <stdlib.h>
     14 #include <string.h>
     15 #include <sys/errno.h>
     16 #include <sys/mman.h>
     17 #include <sys/param.h>
     18 #include <sys/stat.h>
     19 #include <sys/time.h>
     20 #include <sys/types.h>
     21 #include <time.h>
     22 #include <unistd.h>
     23 
     24 #if defined(OS_MACOSX)
     25 #include <AvailabilityMacros.h>
     26 #include "base/mac/foundation_util.h"
     27 #elif !defined(OS_CHROMEOS) && defined(USE_GLIB)
     28 #include <glib.h>  // for g_get_home_dir()
     29 #endif
     30 
     31 #include <fstream>
     32 
     33 #include "base/basictypes.h"
     34 #include "base/files/file_enumerator.h"
     35 #include "base/files/file_path.h"
     36 #include "base/logging.h"
     37 #include "base/memory/scoped_ptr.h"
     38 #include "base/memory/singleton.h"
     39 #include "base/path_service.h"
     40 #include "base/posix/eintr_wrapper.h"
     41 #include "base/stl_util.h"
     42 #include "base/strings/string_util.h"
     43 #include "base/strings/stringprintf.h"
     44 #include "base/strings/sys_string_conversions.h"
     45 #include "base/strings/utf_string_conversions.h"
     46 #include "base/sys_info.h"
     47 #include "base/threading/thread_restrictions.h"
     48 #include "base/time/time.h"
     49 
     50 #if defined(OS_ANDROID)
     51 #include "base/android/content_uri_utils.h"
     52 #include "base/os_compat_android.h"
     53 #endif
     54 
     55 #if !defined(OS_IOS)
     56 #include <grp.h>
     57 #endif
     58 
     59 namespace base {
     60 
     61 namespace {
     62 
     63 #if defined(OS_BSD) || defined(OS_MACOSX)
     64 typedef struct stat stat_wrapper_t;
     65 static int CallStat(const char *path, stat_wrapper_t *sb) {
     66   ThreadRestrictions::AssertIOAllowed();
     67   return stat(path, sb);
     68 }
     69 static int CallLstat(const char *path, stat_wrapper_t *sb) {
     70   ThreadRestrictions::AssertIOAllowed();
     71   return lstat(path, sb);
     72 }
     73 #else
     74 typedef struct stat64 stat_wrapper_t;
     75 static int CallStat(const char *path, stat_wrapper_t *sb) {
     76   ThreadRestrictions::AssertIOAllowed();
     77   return stat64(path, sb);
     78 }
     79 static int CallLstat(const char *path, stat_wrapper_t *sb) {
     80   ThreadRestrictions::AssertIOAllowed();
     81   return lstat64(path, sb);
     82 }
     83 #if defined(OS_ANDROID)
     84 static int CallFstat(int fd, stat_wrapper_t *sb) {
     85   ThreadRestrictions::AssertIOAllowed();
     86   return fstat64(fd, sb);
     87 }
     88 #endif
     89 #endif
     90 
     91 // Helper for NormalizeFilePath(), defined below.
     92 bool RealPath(const FilePath& path, FilePath* real_path) {
     93   ThreadRestrictions::AssertIOAllowed();  // For realpath().
     94   FilePath::CharType buf[PATH_MAX];
     95   if (!realpath(path.value().c_str(), buf))
     96     return false;
     97 
     98   *real_path = FilePath(buf);
     99   return true;
    100 }
    101 
    102 // Helper for VerifyPathControlledByUser.
    103 bool VerifySpecificPathControlledByUser(const FilePath& path,
    104                                         uid_t owner_uid,
    105                                         const std::set<gid_t>& group_gids) {
    106   stat_wrapper_t stat_info;
    107   if (CallLstat(path.value().c_str(), &stat_info) != 0) {
    108     DPLOG(ERROR) << "Failed to get information on path "
    109                  << path.value();
    110     return false;
    111   }
    112 
    113   if (S_ISLNK(stat_info.st_mode)) {
    114     DLOG(ERROR) << "Path " << path.value()
    115                << " is a symbolic link.";
    116     return false;
    117   }
    118 
    119   if (stat_info.st_uid != owner_uid) {
    120     DLOG(ERROR) << "Path " << path.value()
    121                 << " is owned by the wrong user.";
    122     return false;
    123   }
    124 
    125   if ((stat_info.st_mode & S_IWGRP) &&
    126       !ContainsKey(group_gids, stat_info.st_gid)) {
    127     DLOG(ERROR) << "Path " << path.value()
    128                 << " is writable by an unprivileged group.";
    129     return false;
    130   }
    131 
    132   if (stat_info.st_mode & S_IWOTH) {
    133     DLOG(ERROR) << "Path " << path.value()
    134                 << " is writable by any user.";
    135     return false;
    136   }
    137 
    138   return true;
    139 }
    140 
    141 std::string TempFileName() {
    142 #if defined(OS_MACOSX)
    143   return StringPrintf(".%s.XXXXXX", base::mac::BaseBundleID());
    144 #endif
    145 
    146 #if defined(GOOGLE_CHROME_BUILD)
    147   return std::string(".com.google.Chrome.XXXXXX");
    148 #else
    149   return std::string(".org.chromium.Chromium.XXXXXX");
    150 #endif
    151 }
    152 
    153 // Creates and opens a temporary file in |directory|, returning the
    154 // file descriptor. |path| is set to the temporary file path.
    155 // This function does NOT unlink() the file.
    156 int CreateAndOpenFdForTemporaryFile(FilePath directory, FilePath* path) {
    157   ThreadRestrictions::AssertIOAllowed();  // For call to mkstemp().
    158   *path = directory.Append(base::TempFileName());
    159   const std::string& tmpdir_string = path->value();
    160   // this should be OK since mkstemp just replaces characters in place
    161   char* buffer = const_cast<char*>(tmpdir_string.c_str());
    162 
    163   return HANDLE_EINTR(mkstemp(buffer));
    164 }
    165 
    166 #if defined(OS_LINUX)
    167 // Determine if /dev/shm files can be mapped and then mprotect'd PROT_EXEC.
    168 // This depends on the mount options used for /dev/shm, which vary among
    169 // different Linux distributions and possibly local configuration.  It also
    170 // depends on details of kernel--ChromeOS uses the noexec option for /dev/shm
    171 // but its kernel allows mprotect with PROT_EXEC anyway.
    172 bool DetermineDevShmExecutable() {
    173   bool result = false;
    174   FilePath path;
    175   int fd = CreateAndOpenFdForTemporaryFile(FilePath("/dev/shm"), &path);
    176   if (fd >= 0) {
    177     file_util::ScopedFD shm_fd_closer(&fd);
    178     DeleteFile(path, false);
    179     long sysconf_result = sysconf(_SC_PAGESIZE);
    180     CHECK_GE(sysconf_result, 0);
    181     size_t pagesize = static_cast<size_t>(sysconf_result);
    182     CHECK_GE(sizeof(pagesize), sizeof(sysconf_result));
    183     void *mapping = mmap(NULL, pagesize, PROT_READ, MAP_SHARED, fd, 0);
    184     if (mapping != MAP_FAILED) {
    185       if (mprotect(mapping, pagesize, PROT_READ | PROT_EXEC) == 0)
    186         result = true;
    187       munmap(mapping, pagesize);
    188     }
    189   }
    190   return result;
    191 }
    192 #endif  // defined(OS_LINUX)
    193 
    194 }  // namespace
    195 
    196 FilePath MakeAbsoluteFilePath(const FilePath& input) {
    197   ThreadRestrictions::AssertIOAllowed();
    198   char full_path[PATH_MAX];
    199   if (realpath(input.value().c_str(), full_path) == NULL)
    200     return FilePath();
    201   return FilePath(full_path);
    202 }
    203 
    204 // TODO(erikkay): The Windows version of this accepts paths like "foo/bar/*"
    205 // which works both with and without the recursive flag.  I'm not sure we need
    206 // that functionality. If not, remove from file_util_win.cc, otherwise add it
    207 // here.
    208 bool DeleteFile(const FilePath& path, bool recursive) {
    209   ThreadRestrictions::AssertIOAllowed();
    210   const char* path_str = path.value().c_str();
    211   stat_wrapper_t file_info;
    212   int test = CallLstat(path_str, &file_info);
    213   if (test != 0) {
    214     // The Windows version defines this condition as success.
    215     bool ret = (errno == ENOENT || errno == ENOTDIR);
    216     return ret;
    217   }
    218   if (!S_ISDIR(file_info.st_mode))
    219     return (unlink(path_str) == 0);
    220   if (!recursive)
    221     return (rmdir(path_str) == 0);
    222 
    223   bool success = true;
    224   std::stack<std::string> directories;
    225   directories.push(path.value());
    226   FileEnumerator traversal(path, true,
    227       FileEnumerator::FILES | FileEnumerator::DIRECTORIES |
    228       FileEnumerator::SHOW_SYM_LINKS);
    229   for (FilePath current = traversal.Next(); success && !current.empty();
    230        current = traversal.Next()) {
    231     if (traversal.GetInfo().IsDirectory())
    232       directories.push(current.value());
    233     else
    234       success = (unlink(current.value().c_str()) == 0);
    235   }
    236 
    237   while (success && !directories.empty()) {
    238     FilePath dir = FilePath(directories.top());
    239     directories.pop();
    240     success = (rmdir(dir.value().c_str()) == 0);
    241   }
    242   return success;
    243 }
    244 
    245 bool ReplaceFile(const FilePath& from_path,
    246                  const FilePath& to_path,
    247                  PlatformFileError* error) {
    248   ThreadRestrictions::AssertIOAllowed();
    249   if (rename(from_path.value().c_str(), to_path.value().c_str()) == 0)
    250     return true;
    251   if (error)
    252     *error = ErrnoToPlatformFileError(errno);
    253   return false;
    254 }
    255 
    256 bool CopyDirectory(const FilePath& from_path,
    257                    const FilePath& to_path,
    258                    bool recursive) {
    259   ThreadRestrictions::AssertIOAllowed();
    260   // Some old callers of CopyDirectory want it to support wildcards.
    261   // After some discussion, we decided to fix those callers.
    262   // Break loudly here if anyone tries to do this.
    263   // TODO(evanm): remove this once we're sure it's ok.
    264   DCHECK(to_path.value().find('*') == std::string::npos);
    265   DCHECK(from_path.value().find('*') == std::string::npos);
    266 
    267   char top_dir[PATH_MAX];
    268   if (strlcpy(top_dir, from_path.value().c_str(),
    269               arraysize(top_dir)) >= arraysize(top_dir)) {
    270     return false;
    271   }
    272 
    273   // This function does not properly handle destinations within the source
    274   FilePath real_to_path = to_path;
    275   if (PathExists(real_to_path)) {
    276     real_to_path = MakeAbsoluteFilePath(real_to_path);
    277     if (real_to_path.empty())
    278       return false;
    279   } else {
    280     real_to_path = MakeAbsoluteFilePath(real_to_path.DirName());
    281     if (real_to_path.empty())
    282       return false;
    283   }
    284   FilePath real_from_path = MakeAbsoluteFilePath(from_path);
    285   if (real_from_path.empty())
    286     return false;
    287   if (real_to_path.value().size() >= real_from_path.value().size() &&
    288       real_to_path.value().compare(0, real_from_path.value().size(),
    289       real_from_path.value()) == 0)
    290     return false;
    291 
    292   bool success = true;
    293   int traverse_type = FileEnumerator::FILES | FileEnumerator::SHOW_SYM_LINKS;
    294   if (recursive)
    295     traverse_type |= FileEnumerator::DIRECTORIES;
    296   FileEnumerator traversal(from_path, recursive, traverse_type);
    297 
    298   // We have to mimic windows behavior here. |to_path| may not exist yet,
    299   // start the loop with |to_path|.
    300   struct stat from_stat;
    301   FilePath current = from_path;
    302   if (stat(from_path.value().c_str(), &from_stat) < 0) {
    303     DLOG(ERROR) << "CopyDirectory() couldn't stat source directory: "
    304                 << from_path.value() << " errno = " << errno;
    305     success = false;
    306   }
    307   struct stat to_path_stat;
    308   FilePath from_path_base = from_path;
    309   if (recursive && stat(to_path.value().c_str(), &to_path_stat) == 0 &&
    310       S_ISDIR(to_path_stat.st_mode)) {
    311     // If the destination already exists and is a directory, then the
    312     // top level of source needs to be copied.
    313     from_path_base = from_path.DirName();
    314   }
    315 
    316   // The Windows version of this function assumes that non-recursive calls
    317   // will always have a directory for from_path.
    318   DCHECK(recursive || S_ISDIR(from_stat.st_mode));
    319 
    320   while (success && !current.empty()) {
    321     // current is the source path, including from_path, so append
    322     // the suffix after from_path to to_path to create the target_path.
    323     FilePath target_path(to_path);
    324     if (from_path_base != current) {
    325       if (!from_path_base.AppendRelativePath(current, &target_path)) {
    326         success = false;
    327         break;
    328       }
    329     }
    330 
    331     if (S_ISDIR(from_stat.st_mode)) {
    332       if (mkdir(target_path.value().c_str(), from_stat.st_mode & 01777) != 0 &&
    333           errno != EEXIST) {
    334         DLOG(ERROR) << "CopyDirectory() couldn't create directory: "
    335                     << target_path.value() << " errno = " << errno;
    336         success = false;
    337       }
    338     } else if (S_ISREG(from_stat.st_mode)) {
    339       if (!CopyFile(current, target_path)) {
    340         DLOG(ERROR) << "CopyDirectory() couldn't create file: "
    341                     << target_path.value();
    342         success = false;
    343       }
    344     } else {
    345       DLOG(WARNING) << "CopyDirectory() skipping non-regular file: "
    346                     << current.value();
    347     }
    348 
    349     current = traversal.Next();
    350     if (!current.empty())
    351       from_stat = traversal.GetInfo().stat();
    352   }
    353 
    354   return success;
    355 }
    356 
    357 bool PathExists(const FilePath& path) {
    358   ThreadRestrictions::AssertIOAllowed();
    359 #if defined(OS_ANDROID)
    360   if (path.IsContentUri()) {
    361     return ContentUriExists(path);
    362   }
    363 #endif
    364   return access(path.value().c_str(), F_OK) == 0;
    365 }
    366 
    367 bool PathIsWritable(const FilePath& path) {
    368   ThreadRestrictions::AssertIOAllowed();
    369   return access(path.value().c_str(), W_OK) == 0;
    370 }
    371 
    372 bool DirectoryExists(const FilePath& path) {
    373   ThreadRestrictions::AssertIOAllowed();
    374   stat_wrapper_t file_info;
    375   if (CallStat(path.value().c_str(), &file_info) == 0)
    376     return S_ISDIR(file_info.st_mode);
    377   return false;
    378 }
    379 
    380 bool ReadFromFD(int fd, char* buffer, size_t bytes) {
    381   size_t total_read = 0;
    382   while (total_read < bytes) {
    383     ssize_t bytes_read =
    384         HANDLE_EINTR(read(fd, buffer + total_read, bytes - total_read));
    385     if (bytes_read <= 0)
    386       break;
    387     total_read += bytes_read;
    388   }
    389   return total_read == bytes;
    390 }
    391 
    392 bool CreateSymbolicLink(const FilePath& target_path,
    393                         const FilePath& symlink_path) {
    394   DCHECK(!symlink_path.empty());
    395   DCHECK(!target_path.empty());
    396   return ::symlink(target_path.value().c_str(),
    397                    symlink_path.value().c_str()) != -1;
    398 }
    399 
    400 bool ReadSymbolicLink(const FilePath& symlink_path, FilePath* target_path) {
    401   DCHECK(!symlink_path.empty());
    402   DCHECK(target_path);
    403   char buf[PATH_MAX];
    404   ssize_t count = ::readlink(symlink_path.value().c_str(), buf, arraysize(buf));
    405 
    406   if (count <= 0) {
    407     target_path->clear();
    408     return false;
    409   }
    410 
    411   *target_path = FilePath(FilePath::StringType(buf, count));
    412   return true;
    413 }
    414 
    415 bool GetPosixFilePermissions(const FilePath& path, int* mode) {
    416   ThreadRestrictions::AssertIOAllowed();
    417   DCHECK(mode);
    418 
    419   stat_wrapper_t file_info;
    420   // Uses stat(), because on symbolic link, lstat() does not return valid
    421   // permission bits in st_mode
    422   if (CallStat(path.value().c_str(), &file_info) != 0)
    423     return false;
    424 
    425   *mode = file_info.st_mode & FILE_PERMISSION_MASK;
    426   return true;
    427 }
    428 
    429 bool SetPosixFilePermissions(const FilePath& path,
    430                              int mode) {
    431   ThreadRestrictions::AssertIOAllowed();
    432   DCHECK((mode & ~FILE_PERMISSION_MASK) == 0);
    433 
    434   // Calls stat() so that we can preserve the higher bits like S_ISGID.
    435   stat_wrapper_t stat_buf;
    436   if (CallStat(path.value().c_str(), &stat_buf) != 0)
    437     return false;
    438 
    439   // Clears the existing permission bits, and adds the new ones.
    440   mode_t updated_mode_bits = stat_buf.st_mode & ~FILE_PERMISSION_MASK;
    441   updated_mode_bits |= mode & FILE_PERMISSION_MASK;
    442 
    443   if (HANDLE_EINTR(chmod(path.value().c_str(), updated_mode_bits)) != 0)
    444     return false;
    445 
    446   return true;
    447 }
    448 
    449 #if !defined(OS_MACOSX)
    450 // This is implemented in file_util_mac.mm for Mac.
    451 bool GetTempDir(FilePath* path) {
    452   const char* tmp = getenv("TMPDIR");
    453   if (tmp) {
    454     *path = FilePath(tmp);
    455   } else {
    456 #if defined(OS_ANDROID)
    457     return PathService::Get(base::DIR_CACHE, path);
    458 #else
    459     *path = FilePath("/tmp");
    460 #endif
    461   }
    462   return true;
    463 }
    464 #endif  // !defined(OS_MACOSX)
    465 
    466 #if !defined(OS_MACOSX) && !defined(OS_ANDROID)
    467 // This is implemented in file_util_mac.mm and file_util_android.cc for those
    468 // platforms.
    469 bool GetShmemTempDir(bool executable, FilePath* path) {
    470 #if defined(OS_LINUX)
    471   bool use_dev_shm = true;
    472   if (executable) {
    473     static const bool s_dev_shm_executable = DetermineDevShmExecutable();
    474     use_dev_shm = s_dev_shm_executable;
    475   }
    476   if (use_dev_shm) {
    477     *path = FilePath("/dev/shm");
    478     return true;
    479   }
    480 #endif
    481   return GetTempDir(path);
    482 }
    483 #endif  // !defined(OS_MACOSX) && !defined(OS_ANDROID)
    484 
    485 #if !defined(OS_MACOSX)
    486 FilePath GetHomeDir() {
    487 #if defined(OS_CHROMEOS)
    488   if (SysInfo::IsRunningOnChromeOS())
    489     return FilePath("/home/chronos/user");
    490 #endif
    491 
    492   const char* home_dir = getenv("HOME");
    493   if (home_dir && home_dir[0])
    494     return FilePath(home_dir);
    495 
    496 #if defined(OS_ANDROID)
    497   DLOG(WARNING) << "OS_ANDROID: Home directory lookup not yet implemented.";
    498 #elif defined(USE_GLIB) && !defined(OS_CHROMEOS)
    499   // g_get_home_dir calls getpwent, which can fall through to LDAP calls.
    500   ThreadRestrictions::AssertIOAllowed();
    501 
    502   home_dir = g_get_home_dir();
    503   if (home_dir && home_dir[0])
    504     return FilePath(home_dir);
    505 #endif
    506 
    507   FilePath rv;
    508   if (GetTempDir(&rv))
    509     return rv;
    510 
    511   // Last resort.
    512   return FilePath("/tmp");
    513 }
    514 #endif  // !defined(OS_MACOSX)
    515 
    516 bool CreateTemporaryFile(FilePath* path) {
    517   ThreadRestrictions::AssertIOAllowed();  // For call to close().
    518   FilePath directory;
    519   if (!GetTempDir(&directory))
    520     return false;
    521   int fd = CreateAndOpenFdForTemporaryFile(directory, path);
    522   if (fd < 0)
    523     return false;
    524   close(fd);
    525   return true;
    526 }
    527 
    528 FILE* CreateAndOpenTemporaryShmemFile(FilePath* path, bool executable) {
    529   FilePath directory;
    530   if (!GetShmemTempDir(executable, &directory))
    531     return NULL;
    532 
    533   return CreateAndOpenTemporaryFileInDir(directory, path);
    534 }
    535 
    536 FILE* CreateAndOpenTemporaryFileInDir(const FilePath& dir, FilePath* path) {
    537   int fd = CreateAndOpenFdForTemporaryFile(dir, path);
    538   if (fd < 0)
    539     return NULL;
    540 
    541   FILE* file = fdopen(fd, "a+");
    542   if (!file)
    543     close(fd);
    544   return file;
    545 }
    546 
    547 bool CreateTemporaryFileInDir(const FilePath& dir, FilePath* temp_file) {
    548   ThreadRestrictions::AssertIOAllowed();  // For call to close().
    549   int fd = CreateAndOpenFdForTemporaryFile(dir, temp_file);
    550   return ((fd >= 0) && !IGNORE_EINTR(close(fd)));
    551 }
    552 
    553 static bool CreateTemporaryDirInDirImpl(const FilePath& base_dir,
    554                                         const FilePath::StringType& name_tmpl,
    555                                         FilePath* new_dir) {
    556   ThreadRestrictions::AssertIOAllowed();  // For call to mkdtemp().
    557   DCHECK(name_tmpl.find("XXXXXX") != FilePath::StringType::npos)
    558       << "Directory name template must contain \"XXXXXX\".";
    559 
    560   FilePath sub_dir = base_dir.Append(name_tmpl);
    561   std::string sub_dir_string = sub_dir.value();
    562 
    563   // this should be OK since mkdtemp just replaces characters in place
    564   char* buffer = const_cast<char*>(sub_dir_string.c_str());
    565   char* dtemp = mkdtemp(buffer);
    566   if (!dtemp) {
    567     DPLOG(ERROR) << "mkdtemp";
    568     return false;
    569   }
    570   *new_dir = FilePath(dtemp);
    571   return true;
    572 }
    573 
    574 bool CreateTemporaryDirInDir(const FilePath& base_dir,
    575                              const FilePath::StringType& prefix,
    576                              FilePath* new_dir) {
    577   FilePath::StringType mkdtemp_template = prefix;
    578   mkdtemp_template.append(FILE_PATH_LITERAL("XXXXXX"));
    579   return CreateTemporaryDirInDirImpl(base_dir, mkdtemp_template, new_dir);
    580 }
    581 
    582 bool CreateNewTempDirectory(const FilePath::StringType& prefix,
    583                             FilePath* new_temp_path) {
    584   FilePath tmpdir;
    585   if (!GetTempDir(&tmpdir))
    586     return false;
    587 
    588   return CreateTemporaryDirInDirImpl(tmpdir, TempFileName(), new_temp_path);
    589 }
    590 
    591 bool CreateDirectoryAndGetError(const FilePath& full_path,
    592                                 PlatformFileError* error) {
    593   ThreadRestrictions::AssertIOAllowed();  // For call to mkdir().
    594   std::vector<FilePath> subpaths;
    595 
    596   // Collect a list of all parent directories.
    597   FilePath last_path = full_path;
    598   subpaths.push_back(full_path);
    599   for (FilePath path = full_path.DirName();
    600        path.value() != last_path.value(); path = path.DirName()) {
    601     subpaths.push_back(path);
    602     last_path = path;
    603   }
    604 
    605   // Iterate through the parents and create the missing ones.
    606   for (std::vector<FilePath>::reverse_iterator i = subpaths.rbegin();
    607        i != subpaths.rend(); ++i) {
    608     if (DirectoryExists(*i))
    609       continue;
    610     if (mkdir(i->value().c_str(), 0700) == 0)
    611       continue;
    612     // Mkdir failed, but it might have failed with EEXIST, or some other error
    613     // due to the the directory appearing out of thin air. This can occur if
    614     // two processes are trying to create the same file system tree at the same
    615     // time. Check to see if it exists and make sure it is a directory.
    616     int saved_errno = errno;
    617     if (!DirectoryExists(*i)) {
    618       if (error)
    619         *error = ErrnoToPlatformFileError(saved_errno);
    620       return false;
    621     }
    622   }
    623   return true;
    624 }
    625 
    626 bool NormalizeFilePath(const FilePath& path, FilePath* normalized_path) {
    627   FilePath real_path_result;
    628   if (!RealPath(path, &real_path_result))
    629     return false;
    630 
    631   // To be consistant with windows, fail if |real_path_result| is a
    632   // directory.
    633   stat_wrapper_t file_info;
    634   if (CallStat(real_path_result.value().c_str(), &file_info) != 0 ||
    635       S_ISDIR(file_info.st_mode))
    636     return false;
    637 
    638   *normalized_path = real_path_result;
    639   return true;
    640 }
    641 
    642 // TODO(rkc): Refactor GetFileInfo and FileEnumerator to handle symlinks
    643 // correctly. http://code.google.com/p/chromium-os/issues/detail?id=15948
    644 bool IsLink(const FilePath& file_path) {
    645   stat_wrapper_t st;
    646   // If we can't lstat the file, it's safe to assume that the file won't at
    647   // least be a 'followable' link.
    648   if (CallLstat(file_path.value().c_str(), &st) != 0)
    649     return false;
    650 
    651   if (S_ISLNK(st.st_mode))
    652     return true;
    653   else
    654     return false;
    655 }
    656 
    657 bool GetFileInfo(const FilePath& file_path, PlatformFileInfo* results) {
    658   stat_wrapper_t file_info;
    659 #if defined(OS_ANDROID)
    660   if (file_path.IsContentUri()) {
    661     int fd = OpenContentUriForRead(file_path);
    662     if (fd < 0)
    663       return false;
    664     file_util::ScopedFD scoped_fd(&fd);
    665     if (CallFstat(fd, &file_info) != 0)
    666       return false;
    667   } else {
    668 #endif  // defined(OS_ANDROID)
    669     if (CallStat(file_path.value().c_str(), &file_info) != 0)
    670       return false;
    671 #if defined(OS_ANDROID)
    672   }
    673 #endif  // defined(OS_ANDROID)
    674   results->is_directory = S_ISDIR(file_info.st_mode);
    675   results->size = file_info.st_size;
    676 #if defined(OS_MACOSX)
    677   results->last_modified = Time::FromTimeSpec(file_info.st_mtimespec);
    678   results->last_accessed = Time::FromTimeSpec(file_info.st_atimespec);
    679   results->creation_time = Time::FromTimeSpec(file_info.st_ctimespec);
    680 #elif defined(OS_ANDROID)
    681   results->last_modified = Time::FromTimeT(file_info.st_mtime);
    682   results->last_accessed = Time::FromTimeT(file_info.st_atime);
    683   results->creation_time = Time::FromTimeT(file_info.st_ctime);
    684 #else
    685   results->last_modified = Time::FromTimeSpec(file_info.st_mtim);
    686   results->last_accessed = Time::FromTimeSpec(file_info.st_atim);
    687   results->creation_time = Time::FromTimeSpec(file_info.st_ctim);
    688 #endif
    689   return true;
    690 }
    691 
    692 FILE* OpenFile(const FilePath& filename, const char* mode) {
    693   ThreadRestrictions::AssertIOAllowed();
    694   FILE* result = NULL;
    695   do {
    696     result = fopen(filename.value().c_str(), mode);
    697   } while (!result && errno == EINTR);
    698   return result;
    699 }
    700 
    701 int ReadFile(const FilePath& filename, char* data, int size) {
    702   ThreadRestrictions::AssertIOAllowed();
    703   int fd = HANDLE_EINTR(open(filename.value().c_str(), O_RDONLY));
    704   if (fd < 0)
    705     return -1;
    706 
    707   ssize_t bytes_read = HANDLE_EINTR(read(fd, data, size));
    708   if (int ret = IGNORE_EINTR(close(fd)) < 0)
    709     return ret;
    710   return bytes_read;
    711 }
    712 
    713 }  // namespace base
    714 
    715 // -----------------------------------------------------------------------------
    716 
    717 namespace file_util {
    718 
    719 using base::stat_wrapper_t;
    720 using base::CallStat;
    721 using base::CallLstat;
    722 using base::CreateAndOpenFdForTemporaryFile;
    723 using base::DirectoryExists;
    724 using base::FileEnumerator;
    725 using base::FilePath;
    726 using base::MakeAbsoluteFilePath;
    727 using base::VerifySpecificPathControlledByUser;
    728 
    729 base::FilePath MakeUniqueDirectory(const base::FilePath& path) {
    730   const int kMaxAttempts = 20;
    731   for (int attempts = 0; attempts < kMaxAttempts; attempts++) {
    732     int uniquifier =
    733         GetUniquePathNumber(path, base::FilePath::StringType());
    734     if (uniquifier < 0)
    735       break;
    736     base::FilePath test_path = (uniquifier == 0) ? path :
    737         path.InsertBeforeExtensionASCII(
    738             base::StringPrintf(" (%d)", uniquifier));
    739     if (mkdir(test_path.value().c_str(), 0777) == 0)
    740       return test_path;
    741     else if (errno != EEXIST)
    742       break;
    743   }
    744   return base::FilePath();
    745 }
    746 
    747 FILE* OpenFile(const std::string& filename, const char* mode) {
    748   return OpenFile(FilePath(filename), mode);
    749 }
    750 
    751 int WriteFile(const FilePath& filename, const char* data, int size) {
    752   base::ThreadRestrictions::AssertIOAllowed();
    753   int fd = HANDLE_EINTR(creat(filename.value().c_str(), 0666));
    754   if (fd < 0)
    755     return -1;
    756 
    757   int bytes_written = WriteFileDescriptor(fd, data, size);
    758   if (int ret = IGNORE_EINTR(close(fd)) < 0)
    759     return ret;
    760   return bytes_written;
    761 }
    762 
    763 int WriteFileDescriptor(const int fd, const char* data, int size) {
    764   // Allow for partial writes.
    765   ssize_t bytes_written_total = 0;
    766   for (ssize_t bytes_written_partial = 0; bytes_written_total < size;
    767        bytes_written_total += bytes_written_partial) {
    768     bytes_written_partial =
    769         HANDLE_EINTR(write(fd, data + bytes_written_total,
    770                            size - bytes_written_total));
    771     if (bytes_written_partial < 0)
    772       return -1;
    773   }
    774 
    775   return bytes_written_total;
    776 }
    777 
    778 int AppendToFile(const FilePath& filename, const char* data, int size) {
    779   base::ThreadRestrictions::AssertIOAllowed();
    780   int fd = HANDLE_EINTR(open(filename.value().c_str(), O_WRONLY | O_APPEND));
    781   if (fd < 0)
    782     return -1;
    783 
    784   int bytes_written = WriteFileDescriptor(fd, data, size);
    785   if (int ret = IGNORE_EINTR(close(fd)) < 0)
    786     return ret;
    787   return bytes_written;
    788 }
    789 
    790 // Gets the current working directory for the process.
    791 bool GetCurrentDirectory(FilePath* dir) {
    792   // getcwd can return ENOENT, which implies it checks against the disk.
    793   base::ThreadRestrictions::AssertIOAllowed();
    794 
    795   char system_buffer[PATH_MAX] = "";
    796   if (!getcwd(system_buffer, sizeof(system_buffer))) {
    797     NOTREACHED();
    798     return false;
    799   }
    800   *dir = FilePath(system_buffer);
    801   return true;
    802 }
    803 
    804 // Sets the current working directory for the process.
    805 bool SetCurrentDirectory(const FilePath& path) {
    806   base::ThreadRestrictions::AssertIOAllowed();
    807   int ret = chdir(path.value().c_str());
    808   return !ret;
    809 }
    810 
    811 bool VerifyPathControlledByUser(const FilePath& base,
    812                                 const FilePath& path,
    813                                 uid_t owner_uid,
    814                                 const std::set<gid_t>& group_gids) {
    815   if (base != path && !base.IsParent(path)) {
    816      DLOG(ERROR) << "|base| must be a subdirectory of |path|.  base = \""
    817                  << base.value() << "\", path = \"" << path.value() << "\"";
    818      return false;
    819   }
    820 
    821   std::vector<FilePath::StringType> base_components;
    822   std::vector<FilePath::StringType> path_components;
    823 
    824   base.GetComponents(&base_components);
    825   path.GetComponents(&path_components);
    826 
    827   std::vector<FilePath::StringType>::const_iterator ib, ip;
    828   for (ib = base_components.begin(), ip = path_components.begin();
    829        ib != base_components.end(); ++ib, ++ip) {
    830     // |base| must be a subpath of |path|, so all components should match.
    831     // If these CHECKs fail, look at the test that base is a parent of
    832     // path at the top of this function.
    833     DCHECK(ip != path_components.end());
    834     DCHECK(*ip == *ib);
    835   }
    836 
    837   FilePath current_path = base;
    838   if (!VerifySpecificPathControlledByUser(current_path, owner_uid, group_gids))
    839     return false;
    840 
    841   for (; ip != path_components.end(); ++ip) {
    842     current_path = current_path.Append(*ip);
    843     if (!VerifySpecificPathControlledByUser(
    844             current_path, owner_uid, group_gids))
    845       return false;
    846   }
    847   return true;
    848 }
    849 
    850 #if defined(OS_MACOSX) && !defined(OS_IOS)
    851 bool VerifyPathControlledByAdmin(const FilePath& path) {
    852   const unsigned kRootUid = 0;
    853   const FilePath kFileSystemRoot("/");
    854 
    855   // The name of the administrator group on mac os.
    856   const char* const kAdminGroupNames[] = {
    857     "admin",
    858     "wheel"
    859   };
    860 
    861   // Reading the groups database may touch the file system.
    862   base::ThreadRestrictions::AssertIOAllowed();
    863 
    864   std::set<gid_t> allowed_group_ids;
    865   for (int i = 0, ie = arraysize(kAdminGroupNames); i < ie; ++i) {
    866     struct group *group_record = getgrnam(kAdminGroupNames[i]);
    867     if (!group_record) {
    868       DPLOG(ERROR) << "Could not get the group ID of group \""
    869                    << kAdminGroupNames[i] << "\".";
    870       continue;
    871     }
    872 
    873     allowed_group_ids.insert(group_record->gr_gid);
    874   }
    875 
    876   return VerifyPathControlledByUser(
    877       kFileSystemRoot, path, kRootUid, allowed_group_ids);
    878 }
    879 #endif  // defined(OS_MACOSX) && !defined(OS_IOS)
    880 
    881 int GetMaximumPathComponentLength(const FilePath& path) {
    882   base::ThreadRestrictions::AssertIOAllowed();
    883   return pathconf(path.value().c_str(), _PC_NAME_MAX);
    884 }
    885 
    886 }  // namespace file_util
    887 
    888 namespace base {
    889 namespace internal {
    890 
    891 bool MoveUnsafe(const FilePath& from_path, const FilePath& to_path) {
    892   ThreadRestrictions::AssertIOAllowed();
    893   // Windows compatibility: if to_path exists, from_path and to_path
    894   // must be the same type, either both files, or both directories.
    895   stat_wrapper_t to_file_info;
    896   if (CallStat(to_path.value().c_str(), &to_file_info) == 0) {
    897     stat_wrapper_t from_file_info;
    898     if (CallStat(from_path.value().c_str(), &from_file_info) == 0) {
    899       if (S_ISDIR(to_file_info.st_mode) != S_ISDIR(from_file_info.st_mode))
    900         return false;
    901     } else {
    902       return false;
    903     }
    904   }
    905 
    906   if (rename(from_path.value().c_str(), to_path.value().c_str()) == 0)
    907     return true;
    908 
    909   if (!CopyDirectory(from_path, to_path, true))
    910     return false;
    911 
    912   DeleteFile(from_path, true);
    913   return true;
    914 }
    915 
    916 #if !defined(OS_MACOSX)
    917 // Mac has its own implementation, this is for all other Posix systems.
    918 bool CopyFileUnsafe(const FilePath& from_path, const FilePath& to_path) {
    919   ThreadRestrictions::AssertIOAllowed();
    920   int infile = HANDLE_EINTR(open(from_path.value().c_str(), O_RDONLY));
    921   if (infile < 0)
    922     return false;
    923 
    924   int outfile = HANDLE_EINTR(creat(to_path.value().c_str(), 0666));
    925   if (outfile < 0) {
    926     close(infile);
    927     return false;
    928   }
    929 
    930   const size_t kBufferSize = 32768;
    931   std::vector<char> buffer(kBufferSize);
    932   bool result = true;
    933 
    934   while (result) {
    935     ssize_t bytes_read = HANDLE_EINTR(read(infile, &buffer[0], buffer.size()));
    936     if (bytes_read < 0) {
    937       result = false;
    938       break;
    939     }
    940     if (bytes_read == 0)
    941       break;
    942     // Allow for partial writes
    943     ssize_t bytes_written_per_read = 0;
    944     do {
    945       ssize_t bytes_written_partial = HANDLE_EINTR(write(
    946           outfile,
    947           &buffer[bytes_written_per_read],
    948           bytes_read - bytes_written_per_read));
    949       if (bytes_written_partial < 0) {
    950         result = false;
    951         break;
    952       }
    953       bytes_written_per_read += bytes_written_partial;
    954     } while (bytes_written_per_read < bytes_read);
    955   }
    956 
    957   if (IGNORE_EINTR(close(infile)) < 0)
    958     result = false;
    959   if (IGNORE_EINTR(close(outfile)) < 0)
    960     result = false;
    961 
    962   return result;
    963 }
    964 #endif  // !defined(OS_MACOSX)
    965 
    966 }  // namespace internal
    967 }  // namespace base
    968