test_file_util_posix.cc revision 5821806d5e7f356e8fa4b058a389a808ea183019
16f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org// Copyright (c) 2012 The Chromium Authors. All rights reserved.
26f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org// Use of this source code is governed by a BSD-style license that can be
36f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org// found in the LICENSE file.
46f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
56f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#include "base/test/test_file_util.h"
66f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
76f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#include <errno.h>
86f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#include <fcntl.h>
96f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#include <sys/stat.h>
106f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#include <sys/types.h>
116f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
126f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#include <string>
136f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
146f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#include "base/file_path.h"
156f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#include "base/file_util.h"
166f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#include "base/logging.h"
176f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#include "base/string_util.h"
186f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#include "base/utf_string_conversions.h"
196f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
206f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgnamespace file_util {
216f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
226f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgnamespace {
236f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
246f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org// Deny |permission| on the file |path|.
256f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgbool DenyFilePermission(const FilePath& path, mode_t permission) {
266f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  struct stat stat_buf;
276f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  if (stat(path.value().c_str(), &stat_buf) != 0)
286f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    return false;
296f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  stat_buf.st_mode &= ~permission;
306f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
316f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  int rv = HANDLE_EINTR(chmod(path.value().c_str(), stat_buf.st_mode));
326f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  return rv == 0;
336f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
346f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
356f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org// Gets a blob indicating the permission information for |path|.
366f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org// |length| is the length of the blob.  Zero on failure.
376f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org// Returns the blob pointer, or NULL on failure.
386f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgvoid* GetPermissionInfo(const FilePath& path, size_t* length) {
396f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  DCHECK(length);
406f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  *length = 0;
416f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
426f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  struct stat stat_buf;
436f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  if (stat(path.value().c_str(), &stat_buf) != 0)
446f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    return NULL;
456f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
466f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  *length = sizeof(mode_t);
476f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  mode_t* mode = new mode_t;
486f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  *mode = stat_buf.st_mode & ~S_IFMT;  // Filter out file/path kind.
496f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
506f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  return mode;
516f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
526f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
536f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org// Restores the permission information for |path|, given the blob retrieved
546f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org// using |GetPermissionInfo()|.
556f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org// |info| is the pointer to the blob.
566f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org// |length| is the length of the blob.
576f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org// Either |info| or |length| may be NULL/0, in which case nothing happens.
586f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgbool RestorePermissionInfo(const FilePath& path, void* info, size_t length) {
596f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  if (!info || (length == 0))
606f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    return false;
616f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
626f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  DCHECK_EQ(sizeof(mode_t), length);
636f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  mode_t* mode = reinterpret_cast<mode_t*>(info);
646f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
656f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  int rv = HANDLE_EINTR(chmod(path.value().c_str(), *mode));
666f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
676f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  delete mode;
686f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
696f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  return rv == 0;
706f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
716f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
726f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}  // namespace
736f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
746f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgbool DieFileDie(const FilePath& file, bool recurse) {
756f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  // There is no need to workaround Windows problems on POSIX.
766f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  // Just pass-through.
776f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  return file_util::Delete(file, recurse);
786f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
796f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
806f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org// Mostly a verbatim copy of CopyDirectory
816f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgbool CopyRecursiveDirNoCache(const FilePath& source_dir,
826f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                             const FilePath& dest_dir) {
836f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  char top_dir[PATH_MAX];
846f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  if (base::strlcpy(top_dir, source_dir.value().c_str(),
856f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                    arraysize(top_dir)) >= arraysize(top_dir)) {
866f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    return false;
876f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  }
886f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
896f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  // This function does not properly handle destinations within the source
906f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  FilePath real_to_path = dest_dir;
916f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  if (PathExists(real_to_path)) {
926f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    if (!AbsolutePath(&real_to_path))
936f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org      return false;
946f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  } else {
956f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    real_to_path = real_to_path.DirName();
966f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    if (!AbsolutePath(&real_to_path))
976f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org      return false;
986f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  }
996f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  if (real_to_path.value().compare(0, source_dir.value().size(),
1006f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org      source_dir.value()) == 0)
1016f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    return false;
1026f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
1036f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  bool success = true;
1046f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  int traverse_type = FileEnumerator::FILES |
1056f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org      FileEnumerator::SHOW_SYM_LINKS | FileEnumerator::DIRECTORIES;
1066f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  FileEnumerator traversal(source_dir, true, traverse_type);
1076f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
1086f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  // dest_dir may not exist yet, start the loop with dest_dir
1096f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  FileEnumerator::FindInfo info;
1106f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  FilePath current = source_dir;
1116f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  if (stat(source_dir.value().c_str(), &info.stat) < 0) {
1126f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    DLOG(ERROR) << "CopyRecursiveDirNoCache() couldn't stat source directory: "
1136f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                << source_dir.value() << " errno = " << errno;
1146f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    success = false;
1156f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  }
1166f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
1176f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  while (success && !current.empty()) {
1186f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    // |current| is the source path, including source_dir, so paste
1196f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    // the suffix after source_dir onto dest_dir to create the target_path.
1206f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    std::string suffix(&current.value().c_str()[source_dir.value().size()]);
1216f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    // Strip the leading '/' (if any).
1226f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    if (!suffix.empty()) {
1236f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org      DCHECK_EQ('/', suffix[0]);
1246f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org      suffix.erase(0, 1);
1256f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
1266f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    const FilePath target_path = dest_dir.Append(suffix);
1276f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
1286f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    if (S_ISDIR(info.stat.st_mode)) {
1296f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org      if (mkdir(target_path.value().c_str(), info.stat.st_mode & 01777) != 0 &&
1306f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org          errno != EEXIST) {
1316f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        DLOG(ERROR) << "CopyRecursiveDirNoCache() couldn't create directory: "
1326f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                    << target_path.value() << " errno = " << errno;
1336f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        success = false;
1346f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org      }
1356f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    } else if (S_ISREG(info.stat.st_mode)) {
1366f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org      if (CopyFile(current, target_path)) {
1376f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        success = EvictFileFromSystemCache(target_path);
1386f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        DCHECK(success);
1396f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org      } else {
1406f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        DLOG(ERROR) << "CopyRecursiveDirNoCache() couldn't create file: "
1416f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                    << target_path.value();
1426f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        success = false;
1436f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org      }
1446f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    } else {
1456f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org      DLOG(WARNING) << "CopyRecursiveDirNoCache() skipping non-regular file: "
1466f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                    << current.value();
1476f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
1486f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
1496f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    current = traversal.Next();
1506f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    traversal.GetFindInfo(&info);
1516f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  }
1526f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
1536f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  return success;
1546f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
1556f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
1566f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#if !defined(OS_LINUX) && !defined(OS_MACOSX)
1576f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgbool EvictFileFromSystemCache(const FilePath& file) {
1586f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  // There doesn't seem to be a POSIX way to cool the disk cache.
1596f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  NOTIMPLEMENTED();
1606f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  return false;
1616f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
1626f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#endif
1636f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
1646f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgstd::wstring FilePathAsWString(const FilePath& path) {
1656f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  return UTF8ToWide(path.value());
1666f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
1676f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgFilePath WStringAsFilePath(const std::wstring& path) {
1686f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  return FilePath(WideToUTF8(path));
1696f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
1706f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
1716f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgbool MakeFileUnreadable(const FilePath& path) {
1726f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  return DenyFilePermission(path, S_IRUSR | S_IRGRP | S_IROTH);
1736f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
1746f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
1756f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgbool MakeFileUnwritable(const FilePath& path) {
1766f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  return DenyFilePermission(path, S_IWUSR | S_IWGRP | S_IWOTH);
1776f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
1786f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
1796f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgPermissionRestorer::PermissionRestorer(const FilePath& path)
1806f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    : path_(path), info_(NULL), length_(0) {
1816f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  info_ = GetPermissionInfo(path_, &length_);
1826f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  DCHECK(info_ != NULL);
1836f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  DCHECK_NE(0u, length_);
1846f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
1856f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
1866f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgPermissionRestorer::~PermissionRestorer() {
1876f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  if (!RestorePermissionInfo(path_, info_, length_))
1886f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    NOTREACHED();
1896f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
1906f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
1916f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}  // namespace file_util
1926f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org