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