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(¤t.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