diff options
author | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2018-01-31 16:33:43 +0100 |
---|---|---|
committer | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2018-02-06 16:33:22 +0000 |
commit | da51f56cc21233c2d30f0fe0d171727c3102b2e0 (patch) | |
tree | 4e579ab70ce4b19bee7984237f3ce05a96d59d83 /chromium/base/files | |
parent | c8c2d1901aec01e934adf561a9fdf0cc776cdef8 (diff) | |
download | qtwebengine-chromium-da51f56cc21233c2d30f0fe0d171727c3102b2e0.tar.gz |
BASELINE: Update Chromium to 65.0.3525.40
Also imports missing submodules
Change-Id: I36901b7c6a325cda3d2c10cedb2186c25af3b79b
Reviewed-by: Alexandru Croitor <alexandru.croitor@qt.io>
Diffstat (limited to 'chromium/base/files')
-rw-r--r-- | chromium/base/files/dir_reader_posix.h | 4 | ||||
-rw-r--r-- | chromium/base/files/file.cc | 11 | ||||
-rw-r--r-- | chromium/base/files/file.h | 9 | ||||
-rw-r--r-- | chromium/base/files/file_path_watcher_win.cc | 2 | ||||
-rw-r--r-- | chromium/base/files/file_posix.cc | 21 | ||||
-rw-r--r-- | chromium/base/files/file_unittest.cc | 21 | ||||
-rw-r--r-- | chromium/base/files/file_util.h | 8 | ||||
-rw-r--r-- | chromium/base/files/file_util_posix.cc | 209 | ||||
-rw-r--r-- | chromium/base/files/file_util_unittest.cc | 287 | ||||
-rw-r--r-- | chromium/base/files/file_util_win.cc | 230 | ||||
-rw-r--r-- | chromium/base/files/file_win.cc | 25 | ||||
-rw-r--r-- | chromium/base/files/important_file_writer.cc | 28 | ||||
-rw-r--r-- | chromium/base/files/important_file_writer.h | 2 | ||||
-rw-r--r-- | chromium/base/files/memory_mapped_file_win.cc | 2 | ||||
-rw-r--r-- | chromium/base/files/platform_file.h | 2 |
15 files changed, 620 insertions, 241 deletions
diff --git a/chromium/base/files/dir_reader_posix.h b/chromium/base/files/dir_reader_posix.h index 6a32d9fd480..15fc744f6f9 100644 --- a/chromium/base/files/dir_reader_posix.h +++ b/chromium/base/files/dir_reader_posix.h @@ -17,7 +17,7 @@ // seems worse than falling back to enumerating all file descriptors so we will // probably never implement this on the Mac. -#if defined(OS_LINUX) +#if defined(OS_LINUX) || defined(OS_ANDROID) #include "base/files/dir_reader_linux.h" #else #include "base/files/dir_reader_fallback.h" @@ -25,7 +25,7 @@ namespace base { -#if defined(OS_LINUX) +#if defined(OS_LINUX) || defined(OS_ANDROID) typedef DirReaderLinux DirReaderPosix; #else typedef DirReaderFallback DirReaderPosix; diff --git a/chromium/base/files/file.cc b/chromium/base/files/file.cc index 50b4370d309..c1ce182fc6d 100644 --- a/chromium/base/files/file.cc +++ b/chromium/base/files/file.cc @@ -9,6 +9,10 @@ #include "base/timer/elapsed_timer.h" #include "build/build_config.h" +#if defined(OS_POSIX) +#include <errno.h> +#endif + namespace base { File::Info::Info() @@ -82,6 +86,13 @@ File& File::operator=(File&& other) { #if !defined(OS_NACL) void File::Initialize(const FilePath& path, uint32_t flags) { if (path.ReferencesParent()) { +#if defined(OS_WIN) + ::SetLastError(ERROR_ACCESS_DENIED); +#elif defined(OS_POSIX) + errno = EACCES; +#else +#error Unsupported platform +#endif error_details_ = FILE_ERROR_ACCESS_DENIED; return; } diff --git a/chromium/base/files/file.h b/chromium/base/files/file.h index 8b058157611..1b2f6d4cec2 100644 --- a/chromium/base/files/file.h +++ b/chromium/base/files/file.h @@ -24,7 +24,8 @@ namespace base { -#if defined(OS_BSD) || defined(OS_MACOSX) || defined(OS_NACL) +#if defined(OS_BSD) || defined(OS_MACOSX) || defined(OS_NACL) || \ + defined(OS_ANDROID) && __ANDROID_API__ < 21 typedef struct stat stat_wrapper_t; #elif defined(OS_POSIX) typedef struct stat64 stat_wrapper_t; @@ -334,6 +335,12 @@ class BASE_EXPORT File { static Error OSErrorToFileError(int saved_errno); #endif + // Gets the last global error (errno or GetLastError()) and converts it to the + // closest base::File::Error equivalent via OSErrorToFileError(). The returned + // value is only trustworthy immediately after another base::File method + // fails. base::File never resets the global error to zero. + static Error GetLastFileError(); + // Converts an error value to a human-readable form. Used for logging. static std::string ErrorToString(Error error); diff --git a/chromium/base/files/file_path_watcher_win.cc b/chromium/base/files/file_path_watcher_win.cc index 7096c7aa63d..46147509e44 100644 --- a/chromium/base/files/file_path_watcher_win.cc +++ b/chromium/base/files/file_path_watcher_win.cc @@ -15,6 +15,8 @@ #include "base/time/time.h" #include "base/win/object_watcher.h" +#include <windows.h> + namespace base { namespace { diff --git a/chromium/base/files/file_posix.cc b/chromium/base/files/file_posix.cc index 20d59cbc054..d538b667cac 100644 --- a/chromium/base/files/file_posix.cc +++ b/chromium/base/files/file_posix.cc @@ -11,7 +11,7 @@ #include <unistd.h> #include "base/logging.h" -#include "base/metrics/histogram_macros.h" +#include "base/metrics/histogram_functions.h" #include "base/posix/eintr_wrapper.h" #include "base/strings/utf_string_conversions.h" #include "base/threading/thread_restrictions.h" @@ -30,7 +30,8 @@ static_assert(File::FROM_BEGIN == SEEK_SET && File::FROM_CURRENT == SEEK_CUR && namespace { -#if defined(OS_BSD) || defined(OS_MACOSX) || defined(OS_NACL) +#if defined(OS_BSD) || defined(OS_MACOSX) || defined(OS_NACL) || \ + defined(OS_ANDROID) && __ANDROID_API__ < 21 int CallFstat(int fd, stat_wrapper_t *sb) { AssertBlockingAllowed(); return fstat(fd, sb); @@ -78,7 +79,7 @@ File::Error CallFcntlFlock(PlatformFile file, bool do_lock) { lock.l_start = 0; lock.l_len = 0; // Lock entire file. if (HANDLE_EINTR(fcntl(file, F_SETLK, &lock)) == -1) - return File::OSErrorToFileError(errno); + return File::GetLastFileError(); return File::FILE_OK; } #endif @@ -383,7 +384,7 @@ File File::Duplicate() const { PlatformFile other_fd = HANDLE_EINTR(dup(GetPlatformFile())); if (other_fd == -1) - return File(OSErrorToFileError(errno)); + return File(File::GetLastFileError()); File other(other_fd); if (async()) @@ -421,9 +422,10 @@ File::Error File::OSErrorToFileError(int saved_errno) { return FILE_ERROR_NOT_A_DIRECTORY; default: #if !defined(OS_NACL) // NaCl build has no metrics code. - UMA_HISTOGRAM_SPARSE_SLOWLY("PlatformFile.UnknownErrors.Posix", - saved_errno); + UmaHistogramSparse("PlatformFile.UnknownErrors.Posix", saved_errno); #endif + // This function should only be called for errors. + DCHECK_NE(0, saved_errno); return FILE_ERROR_FAILED; } } @@ -501,7 +503,7 @@ void File::DoInitialize(const FilePath& path, uint32_t flags) { } if (descriptor < 0) { - error_details_ = File::OSErrorToFileError(errno); + error_details_ = File::GetLastFileError(); return; } @@ -537,4 +539,9 @@ void File::SetPlatformFile(PlatformFile file) { file_.reset(file); } +// static +File::Error File::GetLastFileError() { + return base::File::OSErrorToFileError(errno); +} + } // namespace base diff --git a/chromium/base/files/file_unittest.cc b/chromium/base/files/file_unittest.cc index 757e1b223cf..1bc09facd03 100644 --- a/chromium/base/files/file_unittest.cc +++ b/chromium/base/files/file_unittest.cc @@ -39,6 +39,7 @@ TEST(FileTest, Create) { File file(file_path, base::File::FLAG_OPEN | base::File::FLAG_READ); EXPECT_FALSE(file.IsValid()); EXPECT_EQ(base::File::FILE_ERROR_NOT_FOUND, file.error_details()); + EXPECT_EQ(base::File::FILE_ERROR_NOT_FOUND, base::File::GetLastFileError()); } { @@ -80,6 +81,7 @@ TEST(FileTest, Create) { EXPECT_FALSE(file.IsValid()); EXPECT_FALSE(file.created()); EXPECT_EQ(base::File::FILE_ERROR_EXISTS, file.error_details()); + EXPECT_EQ(base::File::FILE_ERROR_EXISTS, base::File::GetLastFileError()); } { @@ -237,6 +239,25 @@ TEST(FileTest, ReadWrite) { EXPECT_EQ(data_to_write[i - kOffsetBeyondEndOfFile], data_read_2[i]); } +TEST(FileTest, GetLastFileError) { +#if defined(OS_WIN) + ::SetLastError(ERROR_ACCESS_DENIED); +#else + errno = EACCES; +#endif + EXPECT_EQ(File::FILE_ERROR_ACCESS_DENIED, File::GetLastFileError()); + + base::ScopedTempDir temp_dir; + EXPECT_TRUE(temp_dir.CreateUniqueTempDir()); + + FilePath nonexistent_path(temp_dir.GetPath().AppendASCII("nonexistent")); + File file(nonexistent_path, File::FLAG_OPEN | File::FLAG_READ); + File::Error last_error = File::GetLastFileError(); + EXPECT_FALSE(file.IsValid()); + EXPECT_EQ(File::FILE_ERROR_NOT_FOUND, file.error_details()); + EXPECT_EQ(File::FILE_ERROR_NOT_FOUND, last_error); +} + TEST(FileTest, Append) { base::ScopedTempDir temp_dir; ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); diff --git a/chromium/base/files/file_util.h b/chromium/base/files/file_util.h index 950d24ba000..780bb22cbf5 100644 --- a/chromium/base/files/file_util.h +++ b/chromium/base/files/file_util.h @@ -23,7 +23,7 @@ #include "build/build_config.h" #if defined(OS_WIN) -#include <windows.h> +#include "base/win/windows_types.h" #elif defined(OS_POSIX) #include <sys/stat.h> #include <unistd.h> @@ -130,6 +130,12 @@ BASE_EXPORT bool CopyDirectory(const FilePath& from_path, const FilePath& to_path, bool recursive); +// Like CopyDirectory() except trying to overwrite an existing file will not +// work and will return false. +BASE_EXPORT bool CopyDirectoryExcl(const FilePath& from_path, + const FilePath& to_path, + bool recursive); + // Returns true if the given path exists on the local filesystem, // false otherwise. BASE_EXPORT bool PathExists(const FilePath& path); diff --git a/chromium/base/files/file_util_posix.cc b/chromium/base/files/file_util_posix.cc index 5adac6b4508..27cd58a9df3 100644 --- a/chromium/base/files/file_util_posix.cc +++ b/chromium/base/files/file_util_posix.cc @@ -21,6 +21,8 @@ #include <time.h> #include <unistd.h> +#include "base/base_switches.h" +#include "base/command_line.h" #include "base/containers/stack.h" #include "base/environment.h" #include "base/files/file_enumerator.h" @@ -66,7 +68,8 @@ namespace base { namespace { -#if defined(OS_BSD) || defined(OS_MACOSX) || defined(OS_NACL) +#if defined(OS_BSD) || defined(OS_MACOSX) || defined(OS_NACL) || \ + defined(OS_ANDROID) && __ANDROID_API__ < 21 static int CallStat(const char *path, stat_wrapper_t *sb) { AssertBlockingAllowed(); return stat(path, sb); @@ -75,7 +78,8 @@ static int CallLstat(const char *path, stat_wrapper_t *sb) { AssertBlockingAllowed(); return lstat(path, sb); } -#else // defined(OS_BSD) || defined(OS_MACOSX) || defined(OS_NACL) +#else // defined(OS_BSD) || defined(OS_MACOSX) || defined(OS_NACL) || +// defined(OS_ANDROID) && __ANDROID_API__ < 21 static int CallStat(const char *path, stat_wrapper_t *sb) { AssertBlockingAllowed(); return stat64(path, sb); @@ -217,85 +221,11 @@ bool CopyFileContents(File* infile, File* outfile) { NOTREACHED(); return false; } -#endif // !defined(OS_NACL_NONSFI) - -#if !defined(OS_MACOSX) -// Appends |mode_char| to |mode| before the optional character set encoding; see -// https://www.gnu.org/software/libc/manual/html_node/Opening-Streams.html for -// details. -std::string AppendModeCharacter(StringPiece mode, char mode_char) { - std::string result(mode.as_string()); - size_t comma_pos = result.find(','); - result.insert(comma_pos == std::string::npos ? result.length() : comma_pos, 1, - mode_char); - return result; -} -#endif - -} // namespace - -#if !defined(OS_NACL_NONSFI) -FilePath MakeAbsoluteFilePath(const FilePath& input) { - AssertBlockingAllowed(); - char full_path[PATH_MAX]; - if (realpath(input.value().c_str(), full_path) == nullptr) - return FilePath(); - return FilePath(full_path); -} - -// TODO(erikkay): The Windows version of this accepts paths like "foo/bar/*" -// which works both with and without the recursive flag. I'm not sure we need -// that functionality. If not, remove from file_util_win.cc, otherwise add it -// here. -bool DeleteFile(const FilePath& path, bool recursive) { - AssertBlockingAllowed(); - const char* path_str = path.value().c_str(); - stat_wrapper_t file_info; - if (CallLstat(path_str, &file_info) != 0) { - // The Windows version defines this condition as success. - return (errno == ENOENT || errno == ENOTDIR); - } - if (!S_ISDIR(file_info.st_mode)) - return (unlink(path_str) == 0); - if (!recursive) - return (rmdir(path_str) == 0); - bool success = true; - base::stack<std::string> directories; - directories.push(path.value()); - FileEnumerator traversal(path, true, - FileEnumerator::FILES | FileEnumerator::DIRECTORIES | - FileEnumerator::SHOW_SYM_LINKS); - for (FilePath current = traversal.Next(); !current.empty(); - current = traversal.Next()) { - if (traversal.GetInfo().IsDirectory()) - directories.push(current.value()); - else - success &= (unlink(current.value().c_str()) == 0); - } - - while (!directories.empty()) { - FilePath dir = FilePath(directories.top()); - directories.pop(); - success &= (rmdir(dir.value().c_str()) == 0); - } - return success; -} - -bool ReplaceFile(const FilePath& from_path, - const FilePath& to_path, - File::Error* error) { - AssertBlockingAllowed(); - if (rename(from_path.value().c_str(), to_path.value().c_str()) == 0) - return true; - if (error) - *error = File::OSErrorToFileError(errno); - return false; -} - -bool CopyDirectory(const FilePath& from_path, - const FilePath& to_path, - bool recursive) { +bool DoCopyDirectory(const FilePath& from_path, + const FilePath& to_path, + bool recursive, + bool open_exclusive) { AssertBlockingAllowed(); // Some old callers of CopyDirectory want it to support wildcards. // After some discussion, we decided to fix those callers. @@ -360,12 +290,11 @@ bool CopyDirectory(const FilePath& from_path, } 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) { + mode_t mode = (from_stat.st_mode & 01777) | S_IRUSR | S_IXUSR | S_IWUSR; + if (mkdir(target_path.value().c_str(), mode) == 0) + continue; + if (errno == EEXIST && !open_exclusive) continue; - } DPLOG(ERROR) << "CopyDirectory() couldn't create directory: " << target_path.value(); @@ -397,6 +326,16 @@ bool CopyDirectory(const FilePath& from_path, continue; } + int open_flags = O_WRONLY | O_CREAT; + // If |open_exclusive| is set then we should always create the destination + // file, so O_NONBLOCK is not necessary to ensure we don't block on the + // open call for the target file below, and since the destination will + // always be a regular file it wouldn't affect the behavior of the + // subsequent write calls anyway. + if (open_exclusive) + open_flags |= O_EXCL; + else + open_flags |= O_TRUNC | O_NONBLOCK; // 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 @@ -409,9 +348,7 @@ bool CopyDirectory(const FilePath& from_path, #else int mode = 0600; #endif - base::File outfile( - open(target_path.value().c_str(), - O_WRONLY | O_CREAT | O_TRUNC | O_NONBLOCK, mode)); + base::File outfile(open(target_path.value().c_str(), open_flags, mode)); if (!outfile.IsValid()) { DPLOG(ERROR) << "CopyDirectory() couldn't create file: " << target_path.value(); @@ -428,6 +365,93 @@ bool CopyDirectory(const FilePath& from_path, } #endif // !defined(OS_NACL_NONSFI) +#if !defined(OS_MACOSX) +// Appends |mode_char| to |mode| before the optional character set encoding; see +// https://www.gnu.org/software/libc/manual/html_node/Opening-Streams.html for +// details. +std::string AppendModeCharacter(StringPiece mode, char mode_char) { + std::string result(mode.as_string()); + size_t comma_pos = result.find(','); + result.insert(comma_pos == std::string::npos ? result.length() : comma_pos, 1, + mode_char); + return result; +} +#endif + +} // namespace + +#if !defined(OS_NACL_NONSFI) +FilePath MakeAbsoluteFilePath(const FilePath& input) { + AssertBlockingAllowed(); + char full_path[PATH_MAX]; + if (realpath(input.value().c_str(), full_path) == nullptr) + return FilePath(); + return FilePath(full_path); +} + +// TODO(erikkay): The Windows version of this accepts paths like "foo/bar/*" +// which works both with and without the recursive flag. I'm not sure we need +// that functionality. If not, remove from file_util_win.cc, otherwise add it +// here. +bool DeleteFile(const FilePath& path, bool recursive) { + AssertBlockingAllowed(); + const char* path_str = path.value().c_str(); + stat_wrapper_t file_info; + if (CallLstat(path_str, &file_info) != 0) { + // The Windows version defines this condition as success. + return (errno == ENOENT || errno == ENOTDIR); + } + if (!S_ISDIR(file_info.st_mode)) + return (unlink(path_str) == 0); + if (!recursive) + return (rmdir(path_str) == 0); + + bool success = true; + base::stack<std::string> directories; + directories.push(path.value()); + FileEnumerator traversal(path, true, + FileEnumerator::FILES | FileEnumerator::DIRECTORIES | + FileEnumerator::SHOW_SYM_LINKS); + for (FilePath current = traversal.Next(); !current.empty(); + current = traversal.Next()) { + if (traversal.GetInfo().IsDirectory()) + directories.push(current.value()); + else + success &= (unlink(current.value().c_str()) == 0); + } + + while (!directories.empty()) { + FilePath dir = FilePath(directories.top()); + directories.pop(); + success &= (rmdir(dir.value().c_str()) == 0); + } + return success; +} + +bool ReplaceFile(const FilePath& from_path, + const FilePath& to_path, + File::Error* error) { + AssertBlockingAllowed(); + if (rename(from_path.value().c_str(), to_path.value().c_str()) == 0) + return true; + if (error) + *error = File::GetLastFileError(); + return false; +} + +bool CopyDirectory(const FilePath& from_path, + const FilePath& to_path, + bool recursive) { + return DoCopyDirectory(from_path, to_path, recursive, false); +} + +bool CopyDirectoryExcl(const FilePath& from_path, + const FilePath& to_path, + bool recursive) { + return DoCopyDirectory(from_path, to_path, recursive, true); +} +#endif // !defined(OS_NACL_NONSFI) + bool CreateLocalNonBlockingPipe(int fds[2]) { #if defined(OS_LINUX) return pipe2(fds, O_CLOEXEC | O_NONBLOCK) == 0; @@ -985,16 +1009,21 @@ int GetMaximumPathComponentLength(const FilePath& path) { // This is implemented in file_util_android.cc for that platform. bool GetShmemTempDir(bool executable, FilePath* path) { #if defined(OS_LINUX) || defined(OS_AIX) + bool disable_dev_shm = false; +#if !defined(OS_CHROMEOS) + disable_dev_shm = CommandLine::ForCurrentProcess()->HasSwitch( + switches::kDisableDevShmUsage); +#endif bool use_dev_shm = true; if (executable) { static const bool s_dev_shm_executable = DetermineDevShmExecutable(); use_dev_shm = s_dev_shm_executable; } - if (use_dev_shm) { + if (use_dev_shm && !disable_dev_shm) { *path = FilePath("/dev/shm"); return true; } -#endif +#endif // defined(OS_LINUX) || defined(OS_AIX) return GetTempDir(path); } #endif // !defined(OS_ANDROID) diff --git a/chromium/base/files/file_util_unittest.cc b/chromium/base/files/file_util_unittest.cc index 118e4491927..ae93125d7e1 100644 --- a/chromium/base/files/file_util_unittest.cc +++ b/chromium/base/files/file_util_unittest.cc @@ -1051,6 +1051,92 @@ TEST_F(FileUtilTest, CopyDirectoryPermissionsOverExistingFile) { EXPECT_EQ(0777, mode); } +TEST_F(FileUtilTest, CopyDirectoryExclDoesNotOverwrite) { + // Create source 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)); + + // Create destination 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 the same name. + 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)); + + // Ensure that copying failed and the file was not overwritten. + EXPECT_FALSE(CopyDirectoryExcl(dir_name_from, dir_name_to, false)); + ASSERT_TRUE(PathExists(file_name_to)); + ASSERT_EQ(L"Rigby", ReadTextFile(file_name_to)); +} + +TEST_F(FileUtilTest, CopyDirectoryExclDirectoryOverExistingFile) { + // Create source 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 subdirectory. + FilePath subdir_name_from = dir_name_from.Append(FILE_PATH_LITERAL("Subsub")); + CreateDirectory(subdir_name_from); + ASSERT_TRUE(PathExists(subdir_name_from)); + + // Create destination 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 regular file under the directory with the same name. + FilePath file_name_to = dir_name_to.Append(FILE_PATH_LITERAL("Subsub")); + CreateTextFile(file_name_to, L"Rigby"); + ASSERT_TRUE(PathExists(file_name_to)); + + // Ensure that copying failed and the file was not overwritten. + EXPECT_FALSE(CopyDirectoryExcl(dir_name_from, dir_name_to, false)); + ASSERT_TRUE(PathExists(file_name_to)); + ASSERT_EQ(L"Rigby", ReadTextFile(file_name_to)); +} + +TEST_F(FileUtilTest, CopyDirectoryExclDirectoryOverExistingDirectory) { + // Create source 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 subdirectory. + FilePath subdir_name_from = dir_name_from.Append(FILE_PATH_LITERAL("Subsub")); + CreateDirectory(subdir_name_from); + ASSERT_TRUE(PathExists(subdir_name_from)); + + // Create destination 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 subdirectory under the directory with the same name. + FilePath subdir_name_to = dir_name_to.Append(FILE_PATH_LITERAL("Subsub")); + CreateDirectory(subdir_name_to); + ASSERT_TRUE(PathExists(subdir_name_to)); + + // Ensure that copying failed and the file was not overwritten. + EXPECT_FALSE(CopyDirectoryExcl(dir_name_from, dir_name_to, false)); +} + TEST_F(FileUtilTest, CopyFileExecutablePermission) { FilePath src = temp_dir_.GetPath().Append(FPL("src.txt")); const std::wstring file_contents(L"Gooooooooooooooooooooogle"); @@ -1364,10 +1450,14 @@ TEST_F(FileUtilTest, DeleteDirRecursiveWithOpenFile) { // this is best-effort because it's not supported by all file systems. Both // files will have the same flags so no need to get them individually. int flags; - CHECK_EQ(0, ioctl(file1.GetPlatformFile(), FS_IOC_GETFLAGS, &flags)); - flags |= FS_IMMUTABLE_FL; - ioctl(file1.GetPlatformFile(), FS_IOC_SETFLAGS, &flags); - ioctl(file3.GetPlatformFile(), FS_IOC_SETFLAGS, &flags); + bool file_attrs_supported = + ioctl(file1.GetPlatformFile(), FS_IOC_GETFLAGS, &flags) == 0; + // Some filesystems (e.g. tmpfs) don't support file attributes. + if (file_attrs_supported) { + flags |= FS_IMMUTABLE_FL; + ioctl(file1.GetPlatformFile(), FS_IOC_SETFLAGS, &flags); + ioctl(file3.GetPlatformFile(), FS_IOC_SETFLAGS, &flags); + } #endif // Delete recursively and check that at least the second file got deleted. @@ -1377,9 +1467,11 @@ TEST_F(FileUtilTest, DeleteDirRecursiveWithOpenFile) { #if defined(OS_LINUX) // Make sure that the test can clean up after itself. - flags &= ~FS_IMMUTABLE_FL; - ioctl(file1.GetPlatformFile(), FS_IOC_SETFLAGS, &flags); - ioctl(file3.GetPlatformFile(), FS_IOC_SETFLAGS, &flags); + if (file_attrs_supported) { + flags &= ~FS_IMMUTABLE_FL; + ioctl(file1.GetPlatformFile(), FS_IOC_SETFLAGS, &flags); + ioctl(file3.GetPlatformFile(), FS_IOC_SETFLAGS, &flags); + } #endif } @@ -1776,6 +1868,24 @@ TEST_F(FileUtilTest, CopyFileWithCopyDirectoryRecursiveToExistingDirectory) { EXPECT_TRUE(PathExists(file_name_to)); } +TEST_F(FileUtilTest, CopyFileFailureWithCopyDirectoryExcl) { + // Create a file + FilePath file_name_from = + temp_dir_.GetPath().Append(FILE_PATH_LITERAL("Copy_Test_File.txt")); + CreateTextFile(file_name_from, L"Gooooooooooooooooooooogle"); + ASSERT_TRUE(PathExists(file_name_from)); + + // Make a destination file. + FilePath file_name_to = temp_dir_.GetPath().Append( + FILE_PATH_LITERAL("Copy_Test_File_Destination.txt")); + CreateTextFile(file_name_to, L"Old file content"); + ASSERT_TRUE(PathExists(file_name_to)); + + // Overwriting the destination should fail. + EXPECT_FALSE(CopyDirectoryExcl(file_name_from, file_name_to, true)); + EXPECT_EQ(L"Old file content", ReadTextFile(file_name_to)); +} + TEST_F(FileUtilTest, CopyDirectoryWithTrailingSeparators) { // Create a directory. FilePath dir_name_from = @@ -1863,6 +1973,169 @@ TEST_F(FileUtilTest, CopyDirectoryWithNonRegularFiles) { EXPECT_FALSE(PathExists(symlink_name_to)); EXPECT_FALSE(PathExists(fifo_name_to)); } + +TEST_F(FileUtilTest, CopyDirectoryExclFileOverSymlink) { + // 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 destination directory with a symlink of the same name. + FilePath dir_name_to = + temp_dir_.GetPath().Append(FILE_PATH_LITERAL("Copy_To_Subdir")); + ASSERT_TRUE(CreateDirectory(dir_name_to)); + ASSERT_TRUE(PathExists(dir_name_to)); + + FilePath symlink_target = + dir_name_to.Append(FILE_PATH_LITERAL("Symlink_Target.txt")); + CreateTextFile(symlink_target, L"asdf"); + ASSERT_TRUE(PathExists(symlink_target)); + + FilePath symlink_name_to = + dir_name_to.Append(FILE_PATH_LITERAL("Copy_Test_File.txt")); + ASSERT_TRUE(CreateSymbolicLink(symlink_target, symlink_name_to)); + ASSERT_TRUE(PathExists(symlink_name_to)); + + // Check that copying fails. + EXPECT_FALSE(CopyDirectoryExcl(dir_name_from, dir_name_to, false)); +} + +TEST_F(FileUtilTest, CopyDirectoryExclDirectoryOverSymlink) { + // 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 subdirectory. + FilePath subdir_name_from = dir_name_from.Append(FILE_PATH_LITERAL("Subsub")); + CreateDirectory(subdir_name_from); + ASSERT_TRUE(PathExists(subdir_name_from)); + + // Create a destination directory with a symlink of the same name. + FilePath dir_name_to = + temp_dir_.GetPath().Append(FILE_PATH_LITERAL("Copy_To_Subdir")); + ASSERT_TRUE(CreateDirectory(dir_name_to)); + ASSERT_TRUE(PathExists(dir_name_to)); + + FilePath symlink_target = dir_name_to.Append(FILE_PATH_LITERAL("Subsub")); + CreateTextFile(symlink_target, L"asdf"); + ASSERT_TRUE(PathExists(symlink_target)); + + FilePath symlink_name_to = + dir_name_to.Append(FILE_PATH_LITERAL("Copy_Test_File.txt")); + ASSERT_TRUE(CreateSymbolicLink(symlink_target, symlink_name_to)); + ASSERT_TRUE(PathExists(symlink_name_to)); + + // Check that copying fails. + EXPECT_FALSE(CopyDirectoryExcl(dir_name_from, dir_name_to, false)); +} + +TEST_F(FileUtilTest, CopyDirectoryExclFileOverDanglingSymlink) { + // 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 destination directory with a dangling symlink of the same name. + FilePath dir_name_to = + temp_dir_.GetPath().Append(FILE_PATH_LITERAL("Copy_To_Subdir")); + ASSERT_TRUE(CreateDirectory(dir_name_to)); + ASSERT_TRUE(PathExists(dir_name_to)); + + FilePath symlink_target = + dir_name_to.Append(FILE_PATH_LITERAL("Symlink_Target.txt")); + CreateTextFile(symlink_target, L"asdf"); + ASSERT_TRUE(PathExists(symlink_target)); + + FilePath symlink_name_to = + dir_name_to.Append(FILE_PATH_LITERAL("Copy_Test_File.txt")); + ASSERT_TRUE(CreateSymbolicLink(symlink_target, symlink_name_to)); + ASSERT_TRUE(PathExists(symlink_name_to)); + ASSERT_TRUE(DeleteFile(symlink_target, false)); + + // Check that copying fails and that no file was created for the symlink's + // referent. + EXPECT_FALSE(CopyDirectoryExcl(dir_name_from, dir_name_to, false)); + EXPECT_FALSE(PathExists(symlink_target)); +} + +TEST_F(FileUtilTest, CopyDirectoryExclDirectoryOverDanglingSymlink) { + // 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 subdirectory. + FilePath subdir_name_from = dir_name_from.Append(FILE_PATH_LITERAL("Subsub")); + CreateDirectory(subdir_name_from); + ASSERT_TRUE(PathExists(subdir_name_from)); + + // Create a destination directory with a dangling symlink of the same name. + FilePath dir_name_to = + temp_dir_.GetPath().Append(FILE_PATH_LITERAL("Copy_To_Subdir")); + ASSERT_TRUE(CreateDirectory(dir_name_to)); + ASSERT_TRUE(PathExists(dir_name_to)); + + FilePath symlink_target = + dir_name_to.Append(FILE_PATH_LITERAL("Symlink_Target.txt")); + CreateTextFile(symlink_target, L"asdf"); + ASSERT_TRUE(PathExists(symlink_target)); + + FilePath symlink_name_to = + dir_name_to.Append(FILE_PATH_LITERAL("Copy_Test_File.txt")); + ASSERT_TRUE(CreateSymbolicLink(symlink_target, symlink_name_to)); + ASSERT_TRUE(PathExists(symlink_name_to)); + ASSERT_TRUE(DeleteFile(symlink_target, false)); + + // Check that copying fails and that no directory was created for the + // symlink's referent. + EXPECT_FALSE(CopyDirectoryExcl(dir_name_from, dir_name_to, false)); + EXPECT_FALSE(PathExists(symlink_target)); +} + +TEST_F(FileUtilTest, CopyDirectoryExclFileOverFifo) { + // 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 destination directory with a fifo of the same name. + FilePath dir_name_to = + temp_dir_.GetPath().Append(FILE_PATH_LITERAL("Copy_To_Subdir")); + ASSERT_TRUE(CreateDirectory(dir_name_to)); + ASSERT_TRUE(PathExists(dir_name_to)); + + FilePath fifo_name_to = + dir_name_to.Append(FILE_PATH_LITERAL("Copy_Test_File.txt")); + ASSERT_EQ(0, mkfifo(fifo_name_to.value().c_str(), 0644)); + ASSERT_TRUE(PathExists(fifo_name_to)); + + // Check that copying fails. + EXPECT_FALSE(CopyDirectoryExcl(dir_name_from, dir_name_to, false)); +} #endif // !defined(OS_FUCHSIA) && defined(OS_POSIX) TEST_F(FileUtilTest, CopyFile) { diff --git a/chromium/base/files/file_util_win.cc b/chromium/base/files/file_util_win.cc index 1f63211c1e9..6b268cdb9ad 100644 --- a/chromium/base/files/file_util_win.cc +++ b/chromium/base/files/file_util_win.cc @@ -80,93 +80,43 @@ void AppendModeCharacter(base::char16 mode_char, base::string16* mode) { 1, mode_char); } -} // namespace - -FilePath MakeAbsoluteFilePath(const FilePath& input) { - AssertBlockingAllowed(); - wchar_t file_path[MAX_PATH]; - if (!_wfullpath(file_path, input.value().c_str(), MAX_PATH)) - return FilePath(); - return FilePath(file_path); -} - -bool DeleteFile(const FilePath& path, bool recursive) { +bool DoCopyFile(const FilePath& from_path, + const FilePath& to_path, + bool fail_if_exists) { AssertBlockingAllowed(); - - if (path.empty()) - return true; - - if (path.value().length() >= MAX_PATH) + if (from_path.ReferencesParent() || to_path.ReferencesParent()) return false; - // Handle any path with wildcards. - if (path.BaseName().value().find_first_of(L"*?") != - FilePath::StringType::npos) { - return DeleteFileRecursive(path.DirName(), path.BaseName().value(), - recursive); - } - DWORD attr = GetFileAttributes(path.value().c_str()); - // We're done if we can't find the path. - if (attr == INVALID_FILE_ATTRIBUTES) - return true; - // We may need to clear the read-only bit. - if ((attr & FILE_ATTRIBUTE_READONLY) && - !SetFileAttributes(path.value().c_str(), - attr & ~FILE_ATTRIBUTE_READONLY)) { + // NOTE: I suspect we could support longer paths, but that would involve + // analyzing all our usage of files. + if (from_path.value().length() >= MAX_PATH || + to_path.value().length() >= MAX_PATH) { return false; } - // Directories are handled differently if they're recursive. - if (!(attr & FILE_ATTRIBUTE_DIRECTORY)) - return !!::DeleteFile(path.value().c_str()); - // Handle a simple, single file delete. - if (!recursive || DeleteFileRecursive(path, L"*", true)) - return !!RemoveDirectory(path.value().c_str()); - - return false; -} - -bool DeleteFileAfterReboot(const FilePath& path) { - AssertBlockingAllowed(); - if (path.value().length() >= MAX_PATH) + // Unlike the posix implementation that copies the file manually and discards + // the ACL bits, CopyFile() copies the complete SECURITY_DESCRIPTOR and access + // bits, which is usually not what we want. We can't do much about the + // SECURITY_DESCRIPTOR but at least remove the read only bit. + const wchar_t* dest = to_path.value().c_str(); + if (!::CopyFile(from_path.value().c_str(), dest, fail_if_exists)) { + // Copy failed. return false; - - return MoveFileEx(path.value().c_str(), NULL, - MOVEFILE_DELAY_UNTIL_REBOOT | - MOVEFILE_REPLACE_EXISTING) != FALSE; -} - -bool ReplaceFile(const FilePath& from_path, - const FilePath& to_path, - File::Error* error) { - AssertBlockingAllowed(); - // Try a simple move first. It will only succeed when |to_path| doesn't - // already exist. - if (::MoveFile(from_path.value().c_str(), to_path.value().c_str())) - return true; - File::Error move_error = File::OSErrorToFileError(GetLastError()); - - // Try the full-blown replace if the move fails, as ReplaceFile will only - // succeed when |to_path| does exist. When writing to a network share, we may - // not be able to change the ACLs. Ignore ACL errors then - // (REPLACEFILE_IGNORE_MERGE_ERRORS). - if (::ReplaceFile(to_path.value().c_str(), from_path.value().c_str(), NULL, - REPLACEFILE_IGNORE_MERGE_ERRORS, NULL, NULL)) { - return true; } - // In the case of FILE_ERROR_NOT_FOUND from ReplaceFile, it is likely that - // |to_path| does not exist. In this case, the more relevant error comes - // from the call to MoveFile. - if (error) { - File::Error replace_error = File::OSErrorToFileError(GetLastError()); - *error = replace_error == File::FILE_ERROR_NOT_FOUND ? move_error - : replace_error; + DWORD attrs = GetFileAttributes(dest); + if (attrs == INVALID_FILE_ATTRIBUTES) { + return false; } - return false; + if (attrs & FILE_ATTRIBUTE_READONLY) { + SetFileAttributes(dest, attrs & ~FILE_ATTRIBUTE_READONLY); + } + return true; } -bool CopyDirectory(const FilePath& from_path, const FilePath& to_path, - bool recursive) { +bool DoCopyDirectory(const FilePath& from_path, + const FilePath& to_path, + bool recursive, + bool fail_if_exists) { // NOTE(maruel): Previous version of this function used to call // SHFileOperation(). This used to copy the file attributes and extended // attributes, OLE structured storage, NTFS file system alternate data @@ -239,7 +189,7 @@ bool CopyDirectory(const FilePath& from_path, const FilePath& to_path, << target_path.value().c_str(); success = false; } - } else if (!CopyFile(current, target_path)) { + } else if (!DoCopyFile(current, target_path, fail_if_exists)) { DLOG(ERROR) << "CopyDirectory() couldn't create file: " << target_path.value().c_str(); success = false; @@ -253,6 +203,103 @@ bool CopyDirectory(const FilePath& from_path, const FilePath& to_path, return success; } +} // namespace + +FilePath MakeAbsoluteFilePath(const FilePath& input) { + AssertBlockingAllowed(); + wchar_t file_path[MAX_PATH]; + if (!_wfullpath(file_path, input.value().c_str(), MAX_PATH)) + return FilePath(); + return FilePath(file_path); +} + +bool DeleteFile(const FilePath& path, bool recursive) { + AssertBlockingAllowed(); + + if (path.empty()) + return true; + + if (path.value().length() >= MAX_PATH) + return false; + + // Handle any path with wildcards. + if (path.BaseName().value().find_first_of(L"*?") != + FilePath::StringType::npos) { + return DeleteFileRecursive(path.DirName(), path.BaseName().value(), + recursive); + } + DWORD attr = GetFileAttributes(path.value().c_str()); + // We're done if we can't find the path. + if (attr == INVALID_FILE_ATTRIBUTES) + return true; + // We may need to clear the read-only bit. + if ((attr & FILE_ATTRIBUTE_READONLY) && + !SetFileAttributes(path.value().c_str(), + attr & ~FILE_ATTRIBUTE_READONLY)) { + return false; + } + // Directories are handled differently if they're recursive. + if (!(attr & FILE_ATTRIBUTE_DIRECTORY)) + return !!::DeleteFile(path.value().c_str()); + // Handle a simple, single file delete. + if (!recursive || DeleteFileRecursive(path, L"*", true)) + return !!RemoveDirectory(path.value().c_str()); + + return false; +} + +bool DeleteFileAfterReboot(const FilePath& path) { + AssertBlockingAllowed(); + + if (path.value().length() >= MAX_PATH) + return false; + + return MoveFileEx(path.value().c_str(), NULL, + MOVEFILE_DELAY_UNTIL_REBOOT | + MOVEFILE_REPLACE_EXISTING) != FALSE; +} + +bool ReplaceFile(const FilePath& from_path, + const FilePath& to_path, + File::Error* error) { + AssertBlockingAllowed(); + // Try a simple move first. It will only succeed when |to_path| doesn't + // already exist. + if (::MoveFile(from_path.value().c_str(), to_path.value().c_str())) + return true; + File::Error move_error = File::OSErrorToFileError(GetLastError()); + + // Try the full-blown replace if the move fails, as ReplaceFile will only + // succeed when |to_path| does exist. When writing to a network share, we may + // not be able to change the ACLs. Ignore ACL errors then + // (REPLACEFILE_IGNORE_MERGE_ERRORS). + if (::ReplaceFile(to_path.value().c_str(), from_path.value().c_str(), NULL, + REPLACEFILE_IGNORE_MERGE_ERRORS, NULL, NULL)) { + return true; + } + // In the case of FILE_ERROR_NOT_FOUND from ReplaceFile, it is likely that + // |to_path| does not exist. In this case, the more relevant error comes + // from the call to MoveFile. + if (error) { + File::Error replace_error = File::OSErrorToFileError(GetLastError()); + *error = replace_error == File::FILE_ERROR_NOT_FOUND ? move_error + : replace_error; + } + return false; +} + +bool CopyDirectory(const FilePath& from_path, + const FilePath& to_path, + bool recursive) { + return DoCopyDirectory(from_path, to_path, recursive, false); +} + +bool CopyDirectoryExcl(const FilePath& from_path, + const FilePath& to_path, + bool recursive) { + return DoCopyDirectory(from_path, to_path, recursive, true); +} + bool PathExists(const FilePath& path) { AssertBlockingAllowed(); return (GetFileAttributes(path.value().c_str()) != INVALID_FILE_ATTRIBUTES); @@ -774,34 +821,7 @@ int GetMaximumPathComponentLength(const FilePath& path) { } bool CopyFile(const FilePath& from_path, const FilePath& to_path) { - AssertBlockingAllowed(); - if (from_path.ReferencesParent() || to_path.ReferencesParent()) - return false; - - // NOTE: I suspect we could support longer paths, but that would involve - // analyzing all our usage of files. - if (from_path.value().length() >= MAX_PATH || - to_path.value().length() >= MAX_PATH) { - return false; - } - - // Unlike the posix implementation that copies the file manually and discards - // the ACL bits, CopyFile() copies the complete SECURITY_DESCRIPTOR and access - // bits, which is usually not what we want. We can't do much about the - // SECURITY_DESCRIPTOR but at least remove the read only bit. - const wchar_t* dest = to_path.value().c_str(); - if (!::CopyFile(from_path.value().c_str(), dest, false)) { - // Copy failed. - return false; - } - DWORD attrs = GetFileAttributes(dest); - if (attrs == INVALID_FILE_ATTRIBUTES) { - return false; - } - if (attrs & FILE_ATTRIBUTE_READONLY) { - SetFileAttributes(dest, attrs & ~FILE_ATTRIBUTE_READONLY); - } - return true; + return DoCopyFile(from_path, to_path, false); } bool SetNonBlocking(int fd) { diff --git a/chromium/base/files/file_win.cc b/chromium/base/files/file_win.cc index 6e7c38362d9..d7bffc3b512 100644 --- a/chromium/base/files/file_win.cc +++ b/chromium/base/files/file_win.cc @@ -8,9 +8,11 @@ #include <stdint.h> #include "base/logging.h" -#include "base/metrics/histogram_macros.h" +#include "base/metrics/histogram_functions.h" #include "base/threading/thread_restrictions.h" +#include <windows.h> + namespace base { // Make sure our Whence mappings match the system headers. @@ -234,7 +236,7 @@ File::Error File::Lock() { BOOL result = LockFile(file_.Get(), 0, 0, MAXDWORD, MAXDWORD); if (!result) - return OSErrorToFileError(GetLastError()); + return GetLastFileError(); return FILE_OK; } @@ -245,7 +247,7 @@ File::Error File::Unlock() { BOOL result = UnlockFile(file_.Get(), 0, 0, MAXDWORD, MAXDWORD); if (!result) - return OSErrorToFileError(GetLastError()); + return GetLastFileError(); return FILE_OK; } @@ -264,7 +266,7 @@ File File::Duplicate() const { 0, // dwDesiredAccess ignored due to SAME_ACCESS FALSE, // !bInheritHandle DUPLICATE_SAME_ACCESS)) { - return File(OSErrorToFileError(GetLastError())); + return File(GetLastFileError()); } File other(other_handle); @@ -284,6 +286,7 @@ File::Error File::OSErrorToFileError(DWORD last_error) { switch (last_error) { case ERROR_SHARING_VIOLATION: return FILE_ERROR_IN_USE; + case ERROR_ALREADY_EXISTS: case ERROR_FILE_EXISTS: return FILE_ERROR_EXISTS; case ERROR_FILE_NOT_FOUND: @@ -310,8 +313,9 @@ File::Error File::OSErrorToFileError(DWORD last_error) { case ERROR_DISK_CORRUPT: return FILE_ERROR_IO; default: - UMA_HISTOGRAM_SPARSE_SLOWLY("PlatformFile.UnknownErrors.Windows", - last_error); + UmaHistogramSparse("PlatformFile.UnknownErrors.Windows", last_error); + // This function should only be called for errors. + DCHECK_NE(static_cast<DWORD>(ERROR_SUCCESS), last_error); return FILE_ERROR_FAILED; } } @@ -348,6 +352,8 @@ void File::DoInitialize(const FilePath& path, uint32_t flags) { } if (!disposition) { + ::SetLastError(ERROR_INVALID_PARAMETER); + error_details_ = FILE_ERROR_FAILED; NOTREACHED(); return; } @@ -400,7 +406,7 @@ void File::DoInitialize(const FilePath& path, uint32_t flags) { else if (flags & (FLAG_CREATE_ALWAYS | FLAG_CREATE)) created_ = true; } else { - error_details_ = OSErrorToFileError(GetLastError()); + error_details_ = GetLastFileError(); } } @@ -415,4 +421,9 @@ void File::SetPlatformFile(PlatformFile file) { file_.Set(file); } +// static +File::Error File::GetLastFileError() { + return File::OSErrorToFileError(GetLastError()); +} + } // namespace base diff --git a/chromium/base/files/important_file_writer.cc b/chromium/base/files/important_file_writer.cc index 688b6d2d4ac..64f189d8541 100644 --- a/chromium/base/files/important_file_writer.cc +++ b/chromium/base/files/important_file_writer.cc @@ -99,22 +99,12 @@ void WriteScopedStringToFileAtomically( after_write_callback.Run(result); } -base::File::Error GetLastFileError() { -#if defined(OS_WIN) - return base::File::OSErrorToFileError(::GetLastError()); -#elif defined(OS_POSIX) - return base::File::OSErrorToFileError(errno); -#else - return base::File::FILE_OK; -#endif -} - void DeleteTmpFile(const FilePath& tmp_file_path, StringPiece histogram_suffix) { if (!DeleteFile(tmp_file_path, false)) { - UmaHistogramExactLinearWithSuffix("ImportantFile.FileDeleteError", - histogram_suffix, -GetLastFileError(), - -base::File::FILE_ERROR_MAX); + UmaHistogramExactLinearWithSuffix( + "ImportantFile.FileDeleteError", histogram_suffix, + -base::File::GetLastFileError(), -base::File::FILE_ERROR_MAX); } } @@ -144,9 +134,9 @@ bool ImportantFileWriter::WriteFileAtomically(const FilePath& path, // is securely created. FilePath tmp_file_path; if (!CreateTemporaryFileInDir(path.DirName(), &tmp_file_path)) { - UmaHistogramExactLinearWithSuffix("ImportantFile.FileCreateError", - histogram_suffix, -GetLastFileError(), - -base::File::FILE_ERROR_MAX); + UmaHistogramExactLinearWithSuffix( + "ImportantFile.FileCreateError", histogram_suffix, + -base::File::GetLastFileError(), -base::File::FILE_ERROR_MAX); LogFailure(path, histogram_suffix, FAILED_CREATING, "could not create temporary file"); return false; @@ -167,9 +157,9 @@ bool ImportantFileWriter::WriteFileAtomically(const FilePath& path, const int data_length = checked_cast<int32_t>(data.length()); int bytes_written = tmp_file.Write(0, data.data(), data_length); if (bytes_written < data_length) { - UmaHistogramExactLinearWithSuffix("ImportantFile.FileWriteError", - histogram_suffix, -GetLastFileError(), - -base::File::FILE_ERROR_MAX); + UmaHistogramExactLinearWithSuffix( + "ImportantFile.FileWriteError", histogram_suffix, + -base::File::GetLastFileError(), -base::File::FILE_ERROR_MAX); } bool flush_success = tmp_file.Flush(); tmp_file.Close(); diff --git a/chromium/base/files/important_file_writer.h b/chromium/base/files/important_file_writer.h index 3d04eecbc6f..08a7ee34bee 100644 --- a/chromium/base/files/important_file_writer.h +++ b/chromium/base/files/important_file_writer.h @@ -47,7 +47,7 @@ class BASE_EXPORT ImportantFileWriter { virtual bool SerializeData(std::string* data) = 0; protected: - virtual ~DataSerializer() {} + virtual ~DataSerializer() = default; }; // Save |data| to |path| in an atomic manner. Blocks and writes data on the diff --git a/chromium/base/files/memory_mapped_file_win.cc b/chromium/base/files/memory_mapped_file_win.cc index 087ca9ffe2a..26869f6acdd 100644 --- a/chromium/base/files/memory_mapped_file_win.cc +++ b/chromium/base/files/memory_mapped_file_win.cc @@ -13,6 +13,8 @@ #include "base/strings/string16.h" #include "base/threading/thread_restrictions.h" +#include <windows.h> + namespace base { MemoryMappedFile::MemoryMappedFile() : data_(NULL), length_(0) { diff --git a/chromium/base/files/platform_file.h b/chromium/base/files/platform_file.h index 6b4a0c2199d..4b8b539bf0c 100644 --- a/chromium/base/files/platform_file.h +++ b/chromium/base/files/platform_file.h @@ -9,8 +9,8 @@ #include "build/build_config.h" #if defined(OS_WIN) -#include <windows.h> #include "base/win/scoped_handle.h" +#include "base/win/windows_types.h" #endif // This file defines platform-independent types for dealing with |