diff options
author | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2017-11-20 15:06:40 +0100 |
---|---|---|
committer | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2017-11-22 11:48:58 +0000 |
commit | daa093eea7c773db06799a13bd7e4e2e2a9f8f14 (patch) | |
tree | 96cc5e7b9194c1b29eab927730bfa419e7111c25 /chromium/base/files | |
parent | be59a35641616a4cf23c4a13fa0632624b021c1b (diff) | |
download | qtwebengine-chromium-daa093eea7c773db06799a13bd7e4e2e2a9f8f14.tar.gz |
BASELINE: Update Chromium to 63.0.3239.58
Change-Id: Ia93b322a00ba4dd4004f3bcf1254063ba90e1605
Reviewed-by: Alexandru Croitor <alexandru.croitor@qt.io>
Diffstat (limited to 'chromium/base/files')
-rw-r--r-- | chromium/base/files/file_enumerator.h | 4 | ||||
-rw-r--r-- | chromium/base/files/file_enumerator_unittest.cc | 6 | ||||
-rw-r--r-- | chromium/base/files/file_path.cc | 8 | ||||
-rw-r--r-- | chromium/base/files/file_path.h | 5 | ||||
-rw-r--r-- | chromium/base/files/file_path_unittest.cc | 2 | ||||
-rw-r--r-- | chromium/base/files/file_path_watcher_linux.cc | 13 | ||||
-rw-r--r-- | chromium/base/files/file_posix.cc | 1 | ||||
-rw-r--r-- | chromium/base/files/file_util.h | 24 | ||||
-rw-r--r-- | chromium/base/files/file_util_posix.cc | 162 | ||||
-rw-r--r-- | chromium/base/files/file_util_unittest.cc | 324 |
10 files changed, 449 insertions, 100 deletions
diff --git a/chromium/base/files/file_enumerator.h b/chromium/base/files/file_enumerator.h index 4f3ee57a8c5..190a0612bf7 100644 --- a/chromium/base/files/file_enumerator.h +++ b/chromium/base/files/file_enumerator.h @@ -8,10 +8,10 @@ #include <stddef.h> #include <stdint.h> -#include <stack> #include <vector> #include "base/base_export.h" +#include "base/containers/stack.h" #include "base/files/file_path.h" #include "base/macros.h" #include "base/time/time.h" @@ -164,7 +164,7 @@ class BASE_EXPORT FileEnumerator { // A stack that keeps track of which subdirectories we still need to // enumerate in the breadth-first search. - std::stack<FilePath> pending_paths_; + base::stack<FilePath> pending_paths_; DISALLOW_COPY_AND_ASSIGN(FileEnumerator); }; diff --git a/chromium/base/files/file_enumerator_unittest.cc b/chromium/base/files/file_enumerator_unittest.cc index 5faa80f7611..11df075ecd6 100644 --- a/chromium/base/files/file_enumerator_unittest.cc +++ b/chromium/base/files/file_enumerator_unittest.cc @@ -4,10 +4,10 @@ #include "base/files/file_enumerator.h" -#include <deque> #include <utility> #include <vector> +#include "base/containers/circular_deque.h" #include "base/files/file_path.h" #include "base/files/file_util.h" #include "base/files/scoped_temp_dir.h" @@ -27,13 +27,13 @@ const std::vector<FileEnumerator::FolderSearchPolicy> kFolderSearchPolicies{ FileEnumerator::FolderSearchPolicy::MATCH_ONLY, FileEnumerator::FolderSearchPolicy::ALL}; -std::deque<FilePath> RunEnumerator( +circular_deque<FilePath> RunEnumerator( const FilePath& root_path, bool recursive, int file_type, const FilePath::StringType& pattern, FileEnumerator::FolderSearchPolicy folder_search_policy) { - std::deque<FilePath> rv; + circular_deque<FilePath> rv; FileEnumerator enumerator(root_path, recursive, file_type, pattern, folder_search_policy); for (auto file = enumerator.Next(); !file.empty(); file = enumerator.Next()) diff --git a/chromium/base/files/file_path.cc b/chromium/base/files/file_path.cc index c0d6c1210db..cc3c0d12e66 100644 --- a/chromium/base/files/file_path.cc +++ b/chromium/base/files/file_path.cc @@ -670,14 +670,6 @@ FilePath FilePath::FromUTF16Unsafe(StringPiece16 utf16) { } #endif -void FilePath::GetSizeForPickle(PickleSizer* sizer) const { -#if defined(OS_WIN) - sizer->AddString16(path_); -#else - sizer->AddString(path_); -#endif -} - void FilePath::WriteToPickle(Pickle* pickle) const { #if defined(OS_WIN) pickle->WriteString16(path_); diff --git a/chromium/base/files/file_path.h b/chromium/base/files/file_path.h index a4ced9481a4..6cb2e7577e8 100644 --- a/chromium/base/files/file_path.h +++ b/chromium/base/files/file_path.h @@ -137,7 +137,6 @@ namespace base { class Pickle; class PickleIterator; -class PickleSizer; // An abstraction to isolate users from the differences between native // pathnames on different platforms. @@ -239,7 +238,8 @@ class BASE_EXPORT FilePath { // named by this object, stripping away the file component. If this object // only contains one component, returns a FilePath identifying // kCurrentDirectory. If this object already refers to the root directory, - // returns a FilePath identifying the root directory. + // returns a FilePath identifying the root directory. Please note that this + // doesn't resolve directory navigation, e.g. the result for "../a" is "..". FilePath DirName() const WARN_UNUSED_RESULT; // Returns a FilePath corresponding to the last path component of this @@ -384,7 +384,6 @@ class BASE_EXPORT FilePath { // Similar to FromUTF8Unsafe, but accepts UTF-16 instead. static FilePath FromUTF16Unsafe(StringPiece16 utf16); - void GetSizeForPickle(PickleSizer* sizer) const; void WriteToPickle(Pickle* pickle) const; bool ReadFromPickle(PickleIterator* iter); diff --git a/chromium/base/files/file_path_unittest.cc b/chromium/base/files/file_path_unittest.cc index eba9a96028f..6ca652c5f15 100644 --- a/chromium/base/files/file_path_unittest.cc +++ b/chromium/base/files/file_path_unittest.cc @@ -89,6 +89,7 @@ TEST_F(FilePathTest, DirName) { { FPL("{:"), FPL(".") }, { FPL("\xB3:"), FPL(".") }, { FPL("\xC5:"), FPL(".") }, + { FPL("/aa/../bb/cc"), FPL("/aa/../bb")}, #if defined(OS_WIN) { FPL("\x0143:"), FPL(".") }, #endif // OS_WIN @@ -128,6 +129,7 @@ TEST_F(FilePathTest, DirName) { { FPL("\\\\aa\\bb"), FPL("\\\\aa") }, { FPL("\\\\aa\\"), FPL("\\\\") }, { FPL("\\\\aa"), FPL("\\\\") }, + { FPL("aa\\..\\bb\\c"), FPL("aa\\..\\bb")}, #if defined(FILE_PATH_USES_DRIVE_LETTERS) { FPL("c:\\"), FPL("c:\\") }, { FPL("c:\\\\"), FPL("c:\\\\") }, diff --git a/chromium/base/files/file_path_watcher_linux.cc b/chromium/base/files/file_path_watcher_linux.cc index 9686624b97f..1c1bb3eb3c7 100644 --- a/chromium/base/files/file_path_watcher_linux.cc +++ b/chromium/base/files/file_path_watcher_linux.cc @@ -187,6 +187,12 @@ class FilePathWatcherImpl : public FilePathWatcher::PlatformDelegate { std::unordered_map<InotifyReader::Watch, FilePath> recursive_paths_by_watch_; std::map<FilePath, InotifyReader::Watch> recursive_watches_by_path_; + // Read only while INotifyReader::lock_ is held, and used to post asynchronous + // notifications to the Watcher on its home task_runner(). Ideally this should + // be const, but since it is initialized from |weak_factory_|, which must + // appear after it, that is not possible. + WeakPtr<FilePathWatcherImpl> weak_ptr_; + WeakPtrFactory<FilePathWatcherImpl> weak_factory_; DISALLOW_COPY_AND_ASSIGN(FilePathWatcherImpl); @@ -313,7 +319,9 @@ void InotifyReader::OnInotifyEvent(const inotify_event* event) { } FilePathWatcherImpl::FilePathWatcherImpl() - : recursive_(false), weak_factory_(this) {} + : recursive_(false), weak_factory_(this) { + weak_ptr_ = weak_factory_.GetWeakPtr(); +} FilePathWatcherImpl::~FilePathWatcherImpl() { DCHECK(!task_runner() || task_runner()->RunsTasksInCurrentSequence()); @@ -332,8 +340,7 @@ void FilePathWatcherImpl::OnFilePathChanged(InotifyReader::Watch fired_watch, task_runner()->PostTask( FROM_HERE, BindOnce(&FilePathWatcherImpl::OnFilePathChangedOnOriginSequence, - weak_factory_.GetWeakPtr(), fired_watch, child, created, deleted, - is_dir)); + weak_ptr_, fired_watch, child, created, deleted, is_dir)); } void FilePathWatcherImpl::OnFilePathChangedOnOriginSequence( diff --git a/chromium/base/files/file_posix.cc b/chromium/base/files/file_posix.cc index 3c2346e48fa..6b5d174525c 100644 --- a/chromium/base/files/file_posix.cc +++ b/chromium/base/files/file_posix.cc @@ -410,6 +410,7 @@ File::Error File::OSErrorToFileError(int saved_errno) { return FILE_ERROR_IO; case ENOENT: return FILE_ERROR_NOT_FOUND; + case ENFILE: // fallthrough case EMFILE: return FILE_ERROR_TOO_MANY_OPENED; case ENOMEM: diff --git a/chromium/base/files/file_util.h b/chromium/base/files/file_util.h index fac14d3d499..950d24ba000 100644 --- a/chromium/base/files/file_util.h +++ b/chromium/base/files/file_util.h @@ -95,11 +95,26 @@ BASE_EXPORT bool ReplaceFile(const FilePath& from_path, const FilePath& to_path, File::Error* error); -// Copies a single file. Use CopyDirectory to copy directories. +// Copies a single file. Use CopyDirectory() to copy directories. // This function fails if either path contains traversal components ('..'). +// This function also fails if |to_path| is a directory. // -// This function keeps the metadata on Windows. The read only bit on Windows is -// not kept. +// On POSIX, if |to_path| is a symlink, CopyFile() will follow the symlink. This +// may have security implications. Use with care. +// +// If |to_path| already exists and is a regular file, it will be overwritten, +// though its permissions will stay the same. +// +// If |to_path| does not exist, it will be created. The new file's permissions +// varies per platform: +// +// - This function keeps the metadata on Windows. The read only bit is not kept. +// - On Mac and iOS, |to_path| retains |from_path|'s permissions, except user +// read/write permissions are always set. +// - On Linux and Android, |to_path| has user read/write permissions only. i.e. +// Always 0600. +// - On ChromeOS, |to_path| has user read/write permissions and group/others +// read permissions. i.e. Always 0644. BASE_EXPORT bool CopyFile(const FilePath& from_path, const FilePath& to_path); // Copies the given path, and optionally all subdirectories and their contents @@ -108,8 +123,7 @@ BASE_EXPORT bool CopyFile(const FilePath& from_path, const FilePath& to_path); // If there are files existing under to_path, always overwrite. Returns true // if successful, false otherwise. Wildcards on the names are not supported. // -// This function calls into CopyFile() so the same behavior w.r.t. metadata -// applies. +// This function has the same metadata behavior as CopyFile(). // // If you only need to copy a file use CopyFile, it's faster. BASE_EXPORT bool CopyDirectory(const FilePath& from_path, diff --git a/chromium/base/files/file_util_posix.cc b/chromium/base/files/file_util_posix.cc index de9da50cd01..98887acf996 100644 --- a/chromium/base/files/file_util_posix.cc +++ b/chromium/base/files/file_util_posix.cc @@ -21,6 +21,7 @@ #include <time.h> #include <unistd.h> +#include "base/containers/stack.h" #include "base/environment.h" #include "base/files/file_enumerator.h" #include "base/files/file_path.h" @@ -176,7 +177,46 @@ bool DetermineDevShmExecutable() { } return result; } -#endif // defined(OS_LINUX) +#endif // defined(OS_LINUX) || defined(OS_AIX) + +bool AdvanceEnumeratorWithStat(FileEnumerator* traversal, + FilePath* out_next_path, + struct stat* out_next_stat) { + DCHECK(out_next_path); + DCHECK(out_next_stat); + *out_next_path = traversal->Next(); + if (out_next_path->empty()) + return false; + + *out_next_stat = traversal->GetInfo().stat(); + return true; +} + +bool CopyFileContents(File* infile, File* outfile) { + static constexpr size_t kBufferSize = 32768; + std::vector<char> buffer(kBufferSize); + + for (;;) { + ssize_t bytes_read = infile->ReadAtCurrentPos(buffer.data(), buffer.size()); + if (bytes_read < 0) + return false; + if (bytes_read == 0) + return true; + // Allow for partial writes + ssize_t bytes_written_per_read = 0; + do { + ssize_t bytes_written_partial = outfile->WriteAtCurrentPos( + &buffer[bytes_written_per_read], bytes_read - bytes_written_per_read); + if (bytes_written_partial < 0) + return false; + + bytes_written_per_read += bytes_written_partial; + } while (bytes_written_per_read < bytes_read); + } + + NOTREACHED(); + return false; +} #endif // !defined(OS_NACL_NONSFI) #if !defined(OS_MACOSX) @@ -221,7 +261,7 @@ bool DeleteFile(const FilePath& path, bool recursive) { return (rmdir(path_str) == 0); bool success = true; - std::stack<std::string> directories; + base::stack<std::string> directories; directories.push(path.value()); FileEnumerator traversal(path, true, FileEnumerator::FILES | FileEnumerator::DIRECTORIES | @@ -294,8 +334,8 @@ bool CopyDirectory(const FilePath& from_path, struct stat from_stat; FilePath current = from_path; if (stat(from_path.value().c_str(), &from_stat) < 0) { - DLOG(ERROR) << "CopyDirectory() couldn't stat source directory: " - << from_path.value() << " errno = " << errno; + DPLOG(ERROR) << "CopyDirectory() couldn't stat source directory: " + << from_path.value(); return false; } FilePath from_path_base = from_path; @@ -310,44 +350,81 @@ bool CopyDirectory(const FilePath& from_path, // TODO(maruel): This is not necessary anymore. DCHECK(recursive || S_ISDIR(from_stat.st_mode)); - bool success = true; - while (success && !current.empty()) { + do { // current is the source path, including from_path, so append // the suffix after from_path to to_path to create the target_path. FilePath target_path(to_path); - if (from_path_base != current) { - if (!from_path_base.AppendRelativePath(current, &target_path)) { - success = false; - break; - } + if (from_path_base != current && + !from_path_base.AppendRelativePath(current, &target_path)) { + return false; } if (S_ISDIR(from_stat.st_mode)) { if (mkdir(target_path.value().c_str(), - (from_stat.st_mode & 01777) | S_IRUSR | S_IXUSR | S_IWUSR) != - 0 && - errno != EEXIST) { - DLOG(ERROR) << "CopyDirectory() couldn't create directory: " - << target_path.value() << " errno = " << errno; - success = false; - } - } else if (S_ISREG(from_stat.st_mode)) { - if (!CopyFile(current, target_path)) { - DLOG(ERROR) << "CopyDirectory() couldn't create file: " - << target_path.value(); - success = false; + (from_stat.st_mode & 01777) | S_IRUSR | S_IXUSR | S_IWUSR) == + 0 || + errno == EEXIST) { + continue; } - } else { + + DPLOG(ERROR) << "CopyDirectory() couldn't create directory: " + << target_path.value(); + return false; + } + + if (!S_ISREG(from_stat.st_mode)) { DLOG(WARNING) << "CopyDirectory() skipping non-regular file: " << current.value(); + continue; } - current = traversal.Next(); - if (!current.empty()) - from_stat = traversal.GetInfo().stat(); - } + // Add O_NONBLOCK so we can't block opening a pipe. + base::File infile(open(current.value().c_str(), O_RDONLY | O_NONBLOCK)); + if (!infile.IsValid()) { + DPLOG(ERROR) << "CopyDirectory() couldn't open file: " << current.value(); + return false; + } - return success; + struct stat stat_at_use; + if (fstat(infile.GetPlatformFile(), &stat_at_use) < 0) { + DPLOG(ERROR) << "CopyDirectory() couldn't stat file: " << current.value(); + return false; + } + + if (!S_ISREG(stat_at_use.st_mode)) { + DLOG(WARNING) << "CopyDirectory() skipping non-regular file: " + << current.value(); + continue; + } + + // Each platform has different default file opening modes for CopyFile which + // we want to replicate here. On OS X, we use copyfile(3) which takes the + // source file's permissions into account. On the other platforms, we just + // use the base::File constructor. On Chrome OS, base::File uses a different + // set of permissions than it does on other POSIX platforms. +#if defined(OS_MACOSX) + int mode = 0600 | (stat_at_use.st_mode & 0177); +#elif defined(OS_CHROMEOS) + int mode = 0644; +#else + int mode = 0600; +#endif + base::File outfile( + open(target_path.value().c_str(), + O_WRONLY | O_CREAT | O_TRUNC | O_NONBLOCK, mode)); + if (!outfile.IsValid()) { + DPLOG(ERROR) << "CopyDirectory() couldn't create file: " + << target_path.value(); + return false; + } + + if (!CopyFileContents(&infile, &outfile)) { + DLOG(ERROR) << "CopyDirectory() couldn't copy file: " << current.value(); + return false; + } + } while (AdvanceEnumeratorWithStat(&traversal, ¤t, &from_stat)); + + return true; } #endif // !defined(OS_NACL_NONSFI) @@ -943,32 +1020,7 @@ bool CopyFile(const FilePath& from_path, const FilePath& to_path) { if (!outfile.IsValid()) return false; - const size_t kBufferSize = 32768; - std::vector<char> buffer(kBufferSize); - bool result = true; - - while (result) { - ssize_t bytes_read = infile.ReadAtCurrentPos(&buffer[0], buffer.size()); - if (bytes_read < 0) { - result = false; - break; - } - if (bytes_read == 0) - break; - // Allow for partial writes - ssize_t bytes_written_per_read = 0; - do { - ssize_t bytes_written_partial = outfile.WriteAtCurrentPos( - &buffer[bytes_written_per_read], bytes_read - bytes_written_per_read); - if (bytes_written_partial < 0) { - result = false; - break; - } - bytes_written_per_read += bytes_written_partial; - } while (bytes_written_per_read < bytes_read); - } - - return result; + return CopyFileContents(&infile, &outfile); } #endif // !defined(OS_MACOSX) diff --git a/chromium/base/files/file_util_unittest.cc b/chromium/base/files/file_util_unittest.cc index 5b98069c8ba..3f2e0f0876b 100644 --- a/chromium/base/files/file_util_unittest.cc +++ b/chromium/base/files/file_util_unittest.cc @@ -8,6 +8,7 @@ #include <algorithm> #include <fstream> #include <initializer_list> +#include <memory> #include <set> #include <utility> #include <vector> @@ -632,8 +633,7 @@ TEST_F(FileUtilTest, CreateAndReadSymlinks) { // If we created the link properly, we should be able to read the contents // through it. - std::wstring contents = ReadTextFile(link_from); - EXPECT_EQ(bogus_content, contents); + EXPECT_EQ(bogus_content, ReadTextFile(link_from)); FilePath result; ASSERT_TRUE(ReadSymbolicLink(link_from, &result)); @@ -737,20 +737,46 @@ TEST_F(FileUtilTest, DeleteSymlinkToNonExistentFile) { EXPECT_FALSE(IsLink(file_link)); } +TEST_F(FileUtilTest, CopyFileFollowsSymlinks) { + FilePath link_from = temp_dir_.GetPath().Append(FPL("from_file")); + FilePath link_to = temp_dir_.GetPath().Append(FPL("to_file")); + CreateTextFile(link_to, bogus_content); + + ASSERT_TRUE(CreateSymbolicLink(link_to, link_from)); + + // If we created the link properly, we should be able to read the contents + // through it. + EXPECT_EQ(bogus_content, ReadTextFile(link_from)); + + FilePath result; + ASSERT_TRUE(ReadSymbolicLink(link_from, &result)); + EXPECT_EQ(link_to.value(), result.value()); + + // Create another file and copy it to |link_from|. + FilePath src_file = temp_dir_.GetPath().Append(FPL("src.txt")); + const std::wstring file_contents(L"Gooooooooooooooooooooogle"); + CreateTextFile(src_file, file_contents); + ASSERT_TRUE(CopyFile(src_file, link_from)); + + // Make sure |link_from| is still a symlink, and |link_to| has been written to + // by CopyFile(). + EXPECT_TRUE(IsLink(link_from)); + EXPECT_EQ(file_contents, ReadTextFile(link_from)); + EXPECT_EQ(file_contents, ReadTextFile(link_to)); +} + TEST_F(FileUtilTest, ChangeFilePermissionsAndRead) { // Create a file path. FilePath file_name = temp_dir_.GetPath().Append(FPL("Test Readable File.txt")); EXPECT_FALSE(PathExists(file_name)); - const std::string kData("hello"); - - int buffer_size = kData.length(); - char* buffer = new char[buffer_size]; + static constexpr char kData[] = "hello"; + static constexpr int kDataSize = sizeof(kData) - 1; + char buffer[kDataSize]; // Write file. - EXPECT_EQ(static_cast<int>(kData.length()), - WriteFile(file_name, kData.data(), kData.length())); + EXPECT_EQ(kDataSize, WriteFile(file_name, kData, kDataSize)); EXPECT_TRUE(PathExists(file_name)); // Make sure the file is readable. @@ -763,21 +789,18 @@ TEST_F(FileUtilTest, ChangeFilePermissionsAndRead) { EXPECT_TRUE(GetPosixFilePermissions(file_name, &mode)); EXPECT_FALSE(mode & FILE_PERMISSION_READ_BY_USER); // Make sure the file can't be read. - EXPECT_EQ(-1, ReadFile(file_name, buffer, buffer_size)); + EXPECT_EQ(-1, ReadFile(file_name, buffer, kDataSize)); // Give the read permission. EXPECT_TRUE(SetPosixFilePermissions(file_name, FILE_PERMISSION_READ_BY_USER)); EXPECT_TRUE(GetPosixFilePermissions(file_name, &mode)); EXPECT_TRUE(mode & FILE_PERMISSION_READ_BY_USER); // Make sure the file can be read. - EXPECT_EQ(static_cast<int>(kData.length()), - ReadFile(file_name, buffer, buffer_size)); + EXPECT_EQ(kDataSize, ReadFile(file_name, buffer, kDataSize)); // Delete the file. EXPECT_TRUE(DeleteFile(file_name, false)); EXPECT_FALSE(PathExists(file_name)); - - delete[] buffer; } TEST_F(FileUtilTest, ChangeFilePermissionsAndWrite) { @@ -907,6 +930,193 @@ TEST_F(FileUtilTest, ExecutableExistsInPath) { EXPECT_FALSE(ExecutableExistsInPath(scoped_env.GetEnv(), kDneFileName)); } +TEST_F(FileUtilTest, CopyDirectoryPermissions) { + // Create a directory. + FilePath dir_name_from = + temp_dir_.GetPath().Append(FILE_PATH_LITERAL("Copy_From_Subdir")); + CreateDirectory(dir_name_from); + ASSERT_TRUE(PathExists(dir_name_from)); + + // Create some regular files under the directory with various permissions. + FilePath file_name_from = + dir_name_from.Append(FILE_PATH_LITERAL("Reggy-1.txt")); + CreateTextFile(file_name_from, L"Mordecai"); + ASSERT_TRUE(PathExists(file_name_from)); + ASSERT_TRUE(SetPosixFilePermissions(file_name_from, 0755)); + + FilePath file2_name_from = + dir_name_from.Append(FILE_PATH_LITERAL("Reggy-2.txt")); + CreateTextFile(file2_name_from, L"Rigby"); + ASSERT_TRUE(PathExists(file2_name_from)); + ASSERT_TRUE(SetPosixFilePermissions(file2_name_from, 0777)); + + FilePath file3_name_from = + dir_name_from.Append(FILE_PATH_LITERAL("Reggy-3.txt")); + CreateTextFile(file3_name_from, L"Benson"); + ASSERT_TRUE(PathExists(file3_name_from)); + ASSERT_TRUE(SetPosixFilePermissions(file3_name_from, 0400)); + + // Copy the directory recursively. + FilePath dir_name_to = + temp_dir_.GetPath().Append(FILE_PATH_LITERAL("Copy_To_Subdir")); + FilePath file_name_to = + dir_name_to.Append(FILE_PATH_LITERAL("Reggy-1.txt")); + FilePath file2_name_to = + dir_name_to.Append(FILE_PATH_LITERAL("Reggy-2.txt")); + FilePath file3_name_to = + dir_name_to.Append(FILE_PATH_LITERAL("Reggy-3.txt")); + + ASSERT_FALSE(PathExists(dir_name_to)); + + EXPECT_TRUE(CopyDirectory(dir_name_from, dir_name_to, true)); + ASSERT_TRUE(PathExists(file_name_to)); + ASSERT_TRUE(PathExists(file2_name_to)); + ASSERT_TRUE(PathExists(file3_name_to)); + + int mode = 0; + int expected_mode; + ASSERT_TRUE(GetPosixFilePermissions(file_name_to, &mode)); +#if defined(OS_MACOSX) + expected_mode = 0755; +#elif defined(OS_CHROMEOS) + expected_mode = 0644; +#else + expected_mode = 0600; +#endif + EXPECT_EQ(expected_mode, mode); + + ASSERT_TRUE(GetPosixFilePermissions(file2_name_to, &mode)); +#if defined(OS_MACOSX) + expected_mode = 0755; +#elif defined(OS_CHROMEOS) + expected_mode = 0644; +#else + expected_mode = 0600; +#endif + EXPECT_EQ(expected_mode, mode); + + ASSERT_TRUE(GetPosixFilePermissions(file3_name_to, &mode)); +#if defined(OS_MACOSX) + expected_mode = 0600; +#elif defined(OS_CHROMEOS) + expected_mode = 0644; +#else + expected_mode = 0600; +#endif + EXPECT_EQ(expected_mode, mode); +} + +TEST_F(FileUtilTest, CopyDirectoryPermissionsOverExistingFile) { + // Create a directory. + FilePath dir_name_from = + temp_dir_.GetPath().Append(FILE_PATH_LITERAL("Copy_From_Subdir")); + CreateDirectory(dir_name_from); + ASSERT_TRUE(PathExists(dir_name_from)); + + // Create a file under the directory. + FilePath file_name_from = + dir_name_from.Append(FILE_PATH_LITERAL("Reggy-1.txt")); + CreateTextFile(file_name_from, L"Mordecai"); + ASSERT_TRUE(PathExists(file_name_from)); + ASSERT_TRUE(SetPosixFilePermissions(file_name_from, 0644)); + + // Create a directory. + FilePath dir_name_to = + temp_dir_.GetPath().Append(FILE_PATH_LITERAL("Copy_To_Subdir")); + CreateDirectory(dir_name_to); + ASSERT_TRUE(PathExists(dir_name_to)); + + // Create a file under the directory with wider permissions. + FilePath file_name_to = + dir_name_to.Append(FILE_PATH_LITERAL("Reggy-1.txt")); + CreateTextFile(file_name_to, L"Rigby"); + ASSERT_TRUE(PathExists(file_name_to)); + ASSERT_TRUE(SetPosixFilePermissions(file_name_to, 0777)); + + // Ensure that when we copy the directory, the file contents are copied + // but the permissions on the destination are left alone. + EXPECT_TRUE(CopyDirectory(dir_name_from, dir_name_to, false)); + ASSERT_TRUE(PathExists(file_name_to)); + ASSERT_EQ(L"Mordecai", ReadTextFile(file_name_to)); + + int mode = 0; + ASSERT_TRUE(GetPosixFilePermissions(file_name_to, &mode)); + EXPECT_EQ(0777, mode); +} + +TEST_F(FileUtilTest, CopyFileExecutablePermission) { + FilePath src = temp_dir_.GetPath().Append(FPL("src.txt")); + const std::wstring file_contents(L"Gooooooooooooooooooooogle"); + CreateTextFile(src, file_contents); + + ASSERT_TRUE(SetPosixFilePermissions(src, 0755)); + int mode = 0; + ASSERT_TRUE(GetPosixFilePermissions(src, &mode)); + EXPECT_EQ(0755, mode); + + FilePath dst = temp_dir_.GetPath().Append(FPL("dst.txt")); + ASSERT_TRUE(CopyFile(src, dst)); + EXPECT_EQ(file_contents, ReadTextFile(dst)); + + ASSERT_TRUE(GetPosixFilePermissions(dst, &mode)); + int expected_mode; +#if defined(OS_MACOSX) + expected_mode = 0755; +#elif defined(OS_CHROMEOS) + expected_mode = 0644; +#else + expected_mode = 0600; +#endif + EXPECT_EQ(expected_mode, mode); + ASSERT_TRUE(DeleteFile(dst, false)); + + ASSERT_TRUE(SetPosixFilePermissions(src, 0777)); + ASSERT_TRUE(GetPosixFilePermissions(src, &mode)); + EXPECT_EQ(0777, mode); + + ASSERT_TRUE(CopyFile(src, dst)); + EXPECT_EQ(file_contents, ReadTextFile(dst)); + + ASSERT_TRUE(GetPosixFilePermissions(dst, &mode)); +#if defined(OS_MACOSX) + expected_mode = 0755; +#elif defined(OS_CHROMEOS) + expected_mode = 0644; +#else + expected_mode = 0600; +#endif + EXPECT_EQ(expected_mode, mode); + ASSERT_TRUE(DeleteFile(dst, false)); + + ASSERT_TRUE(SetPosixFilePermissions(src, 0400)); + ASSERT_TRUE(GetPosixFilePermissions(src, &mode)); + EXPECT_EQ(0400, mode); + + ASSERT_TRUE(CopyFile(src, dst)); + EXPECT_EQ(file_contents, ReadTextFile(dst)); + + ASSERT_TRUE(GetPosixFilePermissions(dst, &mode)); +#if defined(OS_MACOSX) + expected_mode = 0600; +#elif defined(OS_CHROMEOS) + expected_mode = 0644; +#else + expected_mode = 0600; +#endif + EXPECT_EQ(expected_mode, mode); + + // This time, do not delete |dst|. Instead set its permissions to 0777. + ASSERT_TRUE(SetPosixFilePermissions(dst, 0777)); + ASSERT_TRUE(GetPosixFilePermissions(dst, &mode)); + EXPECT_EQ(0777, mode); + + // Overwrite it and check the permissions again. + ASSERT_TRUE(CopyFile(src, dst)); + EXPECT_EQ(file_contents, ReadTextFile(dst)); + ASSERT_TRUE(GetPosixFilePermissions(dst, &mode)); + EXPECT_EQ(0777, mode); +} + #endif // !defined(OS_FUCHSIA) && defined(OS_POSIX) #if !defined(OS_FUCHSIA) @@ -1550,12 +1760,64 @@ TEST_F(FileUtilTest, CopyDirectoryWithTrailingSeparators) { EXPECT_TRUE(PathExists(file_name_to)); } +#if !defined(OS_FUCHSIA) && defined(OS_POSIX) +TEST_F(FileUtilTest, CopyDirectoryWithNonRegularFiles) { + // Create a directory. + FilePath dir_name_from = + temp_dir_.GetPath().Append(FILE_PATH_LITERAL("Copy_From_Subdir")); + ASSERT_TRUE(CreateDirectory(dir_name_from)); + ASSERT_TRUE(PathExists(dir_name_from)); + + // Create a file under the directory. + FilePath file_name_from = + dir_name_from.Append(FILE_PATH_LITERAL("Copy_Test_File.txt")); + CreateTextFile(file_name_from, L"Gooooooooooooooooooooogle"); + ASSERT_TRUE(PathExists(file_name_from)); + + // Create a symbolic link under the directory pointing to that file. + FilePath symlink_name_from = + dir_name_from.Append(FILE_PATH_LITERAL("Symlink")); + ASSERT_TRUE(CreateSymbolicLink(file_name_from, symlink_name_from)); + ASSERT_TRUE(PathExists(symlink_name_from)); + + // Create a fifo under the directory. + FilePath fifo_name_from = + dir_name_from.Append(FILE_PATH_LITERAL("Fifo")); + ASSERT_EQ(0, mkfifo(fifo_name_from.value().c_str(), 0644)); + ASSERT_TRUE(PathExists(fifo_name_from)); + + // Copy the directory. + FilePath dir_name_to = + temp_dir_.GetPath().Append(FILE_PATH_LITERAL("Copy_To_Subdir")); + FilePath file_name_to = + dir_name_to.Append(FILE_PATH_LITERAL("Copy_Test_File.txt")); + FilePath symlink_name_to = + dir_name_to.Append(FILE_PATH_LITERAL("Symlink")); + FilePath fifo_name_to = + dir_name_to.Append(FILE_PATH_LITERAL("Fifo")); + + ASSERT_FALSE(PathExists(dir_name_to)); + + EXPECT_TRUE(CopyDirectory(dir_name_from, dir_name_to, false)); + + // Check that only directories and regular files are copied. + EXPECT_TRUE(PathExists(dir_name_from)); + EXPECT_TRUE(PathExists(file_name_from)); + EXPECT_TRUE(PathExists(symlink_name_from)); + EXPECT_TRUE(PathExists(fifo_name_from)); + EXPECT_TRUE(PathExists(dir_name_to)); + EXPECT_TRUE(PathExists(file_name_to)); + EXPECT_FALSE(PathExists(symlink_name_to)); + EXPECT_FALSE(PathExists(fifo_name_to)); +} +#endif // !defined(OS_FUCHSIA) && defined(OS_POSIX) + TEST_F(FileUtilTest, CopyFile) { // Create a directory FilePath dir_name_from = temp_dir_.GetPath().Append(FILE_PATH_LITERAL("Copy_From_Subdir")); - CreateDirectory(dir_name_from); - ASSERT_TRUE(PathExists(dir_name_from)); + ASSERT_TRUE(CreateDirectory(dir_name_from)); + ASSERT_TRUE(DirectoryExists(dir_name_from)); // Create a file under the directory FilePath file_name_from = @@ -1581,10 +1843,31 @@ TEST_F(FileUtilTest, CopyFile) { // Check expected copy results. EXPECT_TRUE(PathExists(file_name_from)); EXPECT_TRUE(PathExists(dest_file)); - const std::wstring read_contents = ReadTextFile(dest_file); - EXPECT_EQ(file_contents, read_contents); + EXPECT_EQ(file_contents, ReadTextFile(dest_file)); EXPECT_FALSE(PathExists(dest_file2_test)); EXPECT_FALSE(PathExists(dest_file2)); + + // Change |file_name_from| contents. + const std::wstring new_file_contents(L"Moogle"); + CreateTextFile(file_name_from, new_file_contents); + ASSERT_TRUE(PathExists(file_name_from)); + EXPECT_EQ(new_file_contents, ReadTextFile(file_name_from)); + + // Overwrite |dest_file|. + ASSERT_TRUE(CopyFile(file_name_from, dest_file)); + EXPECT_TRUE(PathExists(dest_file)); + EXPECT_EQ(new_file_contents, ReadTextFile(dest_file)); + + // Create another directory. + FilePath dest_dir = temp_dir_.GetPath().Append(FPL("dest_dir")); + ASSERT_TRUE(CreateDirectory(dest_dir)); + EXPECT_TRUE(DirectoryExists(dest_dir)); + EXPECT_TRUE(IsDirectoryEmpty(dest_dir)); + + // Make sure CopyFile() cannot overwrite a directory. + ASSERT_FALSE(CopyFile(file_name_from, dest_dir)); + EXPECT_TRUE(DirectoryExists(dest_dir)); + EXPECT_TRUE(IsDirectoryEmpty(dest_dir)); } // file_util winds up using autoreleased objects on the Mac, so this needs @@ -2584,7 +2867,7 @@ TEST_F(FileUtilTest, ValidContentUriTest) { FilePath image_file = data_dir.Append(FILE_PATH_LITERAL("red.png")); int64_t image_size; GetFileSize(image_file, &image_size); - EXPECT_LT(0, image_size); + ASSERT_GT(image_size, 0); // Insert the image into MediaStore. MediaStore will do some conversions, and // return the content URI. @@ -2598,11 +2881,10 @@ TEST_F(FileUtilTest, ValidContentUriTest) { EXPECT_EQ(image_size, content_uri_size); // We should be able to read the file. - char* buffer = new char[image_size]; File file = OpenContentUriForRead(path); EXPECT_TRUE(file.IsValid()); - EXPECT_TRUE(file.ReadAtCurrentPos(buffer, image_size)); - delete[] buffer; + auto buffer = std::make_unique<char[]>(image_size); + EXPECT_TRUE(file.ReadAtCurrentPos(buffer.get(), image_size)); } TEST_F(FileUtilTest, NonExistentContentUriTest) { |