summaryrefslogtreecommitdiff
path: root/chromium/base/files
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@qt.io>2018-01-31 16:33:43 +0100
committerAllan Sandfeld Jensen <allan.jensen@qt.io>2018-02-06 16:33:22 +0000
commitda51f56cc21233c2d30f0fe0d171727c3102b2e0 (patch)
tree4e579ab70ce4b19bee7984237f3ce05a96d59d83 /chromium/base/files
parentc8c2d1901aec01e934adf561a9fdf0cc776cdef8 (diff)
downloadqtwebengine-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.h4
-rw-r--r--chromium/base/files/file.cc11
-rw-r--r--chromium/base/files/file.h9
-rw-r--r--chromium/base/files/file_path_watcher_win.cc2
-rw-r--r--chromium/base/files/file_posix.cc21
-rw-r--r--chromium/base/files/file_unittest.cc21
-rw-r--r--chromium/base/files/file_util.h8
-rw-r--r--chromium/base/files/file_util_posix.cc209
-rw-r--r--chromium/base/files/file_util_unittest.cc287
-rw-r--r--chromium/base/files/file_util_win.cc230
-rw-r--r--chromium/base/files/file_win.cc25
-rw-r--r--chromium/base/files/important_file_writer.cc28
-rw-r--r--chromium/base/files/important_file_writer.h2
-rw-r--r--chromium/base/files/memory_mapped_file_win.cc2
-rw-r--r--chromium/base/files/platform_file.h2
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