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