| Index: base/file_util_win.cc
|
| diff --git a/base/file_util_win.cc b/base/file_util_win.cc
|
| index 2a56ea9468485f60ffc887b0e496d68467e03b78..928b66e525b16bd0f70426a0f625067a8a854ffc 100644
|
| --- a/base/file_util_win.cc
|
| +++ b/base/file_util_win.cc
|
| @@ -34,6 +34,44 @@ namespace {
|
| const DWORD kFileShareAll =
|
| FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
|
|
|
| +bool ShellCopy(const FilePath& from_path,
|
| + const FilePath& to_path,
|
| + bool recursive) {
|
| + // WinXP SHFileOperation doesn't like trailing separators.
|
| + FilePath stripped_from = from_path.StripTrailingSeparators();
|
| + FilePath stripped_to = to_path.StripTrailingSeparators();
|
| +
|
| + ThreadRestrictions::AssertIOAllowed();
|
| +
|
| + // NOTE: I suspect we could support longer paths, but that would involve
|
| + // analyzing all our usage of files.
|
| + if (stripped_from.value().length() >= MAX_PATH ||
|
| + stripped_to.value().length() >= MAX_PATH) {
|
| + return false;
|
| + }
|
| +
|
| + // SHFILEOPSTRUCT wants the path to be terminated with two NULLs,
|
| + // so we have to use wcscpy because wcscpy_s writes non-NULLs
|
| + // into the rest of the buffer.
|
| + wchar_t double_terminated_path_from[MAX_PATH + 1] = {0};
|
| + wchar_t double_terminated_path_to[MAX_PATH + 1] = {0};
|
| +#pragma warning(suppress:4996) // don't complain about wcscpy deprecation
|
| + wcscpy(double_terminated_path_from, stripped_from.value().c_str());
|
| +#pragma warning(suppress:4996) // don't complain about wcscpy deprecation
|
| + wcscpy(double_terminated_path_to, stripped_to.value().c_str());
|
| +
|
| + SHFILEOPSTRUCT file_operation = {0};
|
| + file_operation.wFunc = FO_COPY;
|
| + file_operation.pFrom = double_terminated_path_from;
|
| + file_operation.pTo = double_terminated_path_to;
|
| + file_operation.fFlags = FOF_NOERRORUI | FOF_SILENT | FOF_NOCONFIRMATION |
|
| + FOF_NOCONFIRMMKDIR;
|
| + if (!recursive)
|
| + file_operation.fFlags |= FOF_NORECURSION | FOF_FILESONLY;
|
| +
|
| + return (SHFileOperation(&file_operation) == 0);
|
| +}
|
| +
|
| } // namespace
|
|
|
| FilePath MakeAbsoluteFilePath(const FilePath& input) {
|
| @@ -109,40 +147,6 @@ bool DeleteAfterReboot(const FilePath& path) {
|
| MOVEFILE_REPLACE_EXISTING) != FALSE;
|
| }
|
|
|
| -bool MoveUnsafe(const FilePath& from_path, const FilePath& to_path) {
|
| - ThreadRestrictions::AssertIOAllowed();
|
| -
|
| - // 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;
|
| - }
|
| - if (MoveFileEx(from_path.value().c_str(), to_path.value().c_str(),
|
| - MOVEFILE_COPY_ALLOWED | MOVEFILE_REPLACE_EXISTING) != 0)
|
| - return true;
|
| -
|
| - // Keep the last error value from MoveFileEx around in case the below
|
| - // fails.
|
| - bool ret = false;
|
| - DWORD last_error = ::GetLastError();
|
| -
|
| - if (file_util::DirectoryExists(from_path)) {
|
| - // MoveFileEx fails if moving directory across volumes. We will simulate
|
| - // the move by using Copy and Delete. Ideally we could check whether
|
| - // from_path and to_path are indeed in different volumes.
|
| - ret = file_util::CopyAndDeleteDirectory(from_path, to_path);
|
| - }
|
| -
|
| - if (!ret) {
|
| - // Leave a clue about what went wrong so that it can be (at least) picked
|
| - // up by a PLOG entry.
|
| - ::SetLastError(last_error);
|
| - }
|
| -
|
| - return ret;
|
| -}
|
| -
|
| bool ReplaceFile(const FilePath& from_path,
|
| const FilePath& to_path,
|
| PlatformFileError* error) {
|
| @@ -164,82 +168,23 @@ bool ReplaceFile(const FilePath& from_path,
|
| return false;
|
| }
|
|
|
| -} // namespace base
|
| -
|
| -// -----------------------------------------------------------------------------
|
| -
|
| -namespace file_util {
|
| -
|
| -using base::FilePath;
|
| -using base::kFileShareAll;
|
| -
|
| -bool CopyFileUnsafe(const FilePath& from_path, const FilePath& to_path) {
|
| - base::ThreadRestrictions::AssertIOAllowed();
|
| -
|
| - // 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;
|
| - }
|
| - return (::CopyFile(from_path.value().c_str(), to_path.value().c_str(),
|
| - false) != 0);
|
| -}
|
| -
|
| -bool ShellCopy(const FilePath& from_path, const FilePath& to_path,
|
| - bool recursive) {
|
| - // WinXP SHFileOperation doesn't like trailing separators.
|
| - FilePath stripped_from = from_path.StripTrailingSeparators();
|
| - FilePath stripped_to = to_path.StripTrailingSeparators();
|
| -
|
| - base::ThreadRestrictions::AssertIOAllowed();
|
| -
|
| - // NOTE: I suspect we could support longer paths, but that would involve
|
| - // analyzing all our usage of files.
|
| - if (stripped_from.value().length() >= MAX_PATH ||
|
| - stripped_to.value().length() >= MAX_PATH) {
|
| - return false;
|
| - }
|
| -
|
| - // SHFILEOPSTRUCT wants the path to be terminated with two NULLs,
|
| - // so we have to use wcscpy because wcscpy_s writes non-NULLs
|
| - // into the rest of the buffer.
|
| - wchar_t double_terminated_path_from[MAX_PATH + 1] = {0};
|
| - wchar_t double_terminated_path_to[MAX_PATH + 1] = {0};
|
| -#pragma warning(suppress:4996) // don't complain about wcscpy deprecation
|
| - wcscpy(double_terminated_path_from, stripped_from.value().c_str());
|
| -#pragma warning(suppress:4996) // don't complain about wcscpy deprecation
|
| - wcscpy(double_terminated_path_to, stripped_to.value().c_str());
|
| -
|
| - SHFILEOPSTRUCT file_operation = {0};
|
| - file_operation.wFunc = FO_COPY;
|
| - file_operation.pFrom = double_terminated_path_from;
|
| - file_operation.pTo = double_terminated_path_to;
|
| - file_operation.fFlags = FOF_NOERRORUI | FOF_SILENT | FOF_NOCONFIRMATION |
|
| - FOF_NOCONFIRMMKDIR;
|
| - if (!recursive)
|
| - file_operation.fFlags |= FOF_NORECURSION | FOF_FILESONLY;
|
| -
|
| - return (SHFileOperation(&file_operation) == 0);
|
| -}
|
| -
|
| bool CopyDirectory(const FilePath& from_path, const FilePath& to_path,
|
| bool recursive) {
|
| - base::ThreadRestrictions::AssertIOAllowed();
|
| + ThreadRestrictions::AssertIOAllowed();
|
|
|
| if (recursive)
|
| return ShellCopy(from_path, to_path, true);
|
|
|
| // The following code assumes that from path is a directory.
|
| - DCHECK(DirectoryExists(from_path));
|
| + DCHECK(file_util::DirectoryExists(from_path));
|
|
|
| // Instead of creating a new directory, we copy the old one to include the
|
| // security information of the folder as part of the copy.
|
| - if (!PathExists(to_path)) {
|
| + if (!file_util::PathExists(to_path)) {
|
| // Except that Vista fails to do that, and instead do a recursive copy if
|
| // the target directory doesn't exist.
|
| if (base::win::GetVersion() >= base::win::VERSION_VISTA)
|
| - CreateDirectory(to_path);
|
| + file_util::CreateDirectory(to_path);
|
| else
|
| ShellCopy(from_path, to_path, false);
|
| }
|
| @@ -248,21 +193,14 @@ bool CopyDirectory(const FilePath& from_path, const FilePath& to_path,
|
| return ShellCopy(directory, to_path, false);
|
| }
|
|
|
| -bool CopyAndDeleteDirectory(const FilePath& from_path,
|
| - const FilePath& to_path) {
|
| - base::ThreadRestrictions::AssertIOAllowed();
|
| - if (CopyDirectory(from_path, to_path, true)) {
|
| - if (Delete(from_path, true)) {
|
| - return true;
|
| - }
|
| - // Like Move, this function is not transactional, so we just
|
| - // leave the copied bits behind if deleting from_path fails.
|
| - // If to_path exists previously then we have already overwritten
|
| - // it by now, we don't get better off by deleting the new bits.
|
| - }
|
| - return false;
|
| -}
|
| +} // namespace base
|
| +
|
| +// -----------------------------------------------------------------------------
|
| +
|
| +namespace file_util {
|
|
|
| +using base::FilePath;
|
| +using base::kFileShareAll;
|
|
|
| bool PathExists(const FilePath& path) {
|
| base::ThreadRestrictions::AssertIOAllowed();
|
| @@ -750,3 +688,71 @@ int GetMaximumPathComponentLength(const FilePath& path) {
|
| }
|
|
|
| } // namespace file_util
|
| +
|
| +namespace base {
|
| +namespace internal {
|
| +
|
| +bool MoveUnsafe(const FilePath& from_path, const FilePath& to_path) {
|
| + ThreadRestrictions::AssertIOAllowed();
|
| +
|
| + // 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;
|
| + }
|
| + if (MoveFileEx(from_path.value().c_str(), to_path.value().c_str(),
|
| + MOVEFILE_COPY_ALLOWED | MOVEFILE_REPLACE_EXISTING) != 0)
|
| + return true;
|
| +
|
| + // Keep the last error value from MoveFileEx around in case the below
|
| + // fails.
|
| + bool ret = false;
|
| + DWORD last_error = ::GetLastError();
|
| +
|
| + if (file_util::DirectoryExists(from_path)) {
|
| + // MoveFileEx fails if moving directory across volumes. We will simulate
|
| + // the move by using Copy and Delete. Ideally we could check whether
|
| + // from_path and to_path are indeed in different volumes.
|
| + ret = internal::CopyAndDeleteDirectory(from_path, to_path);
|
| + }
|
| +
|
| + if (!ret) {
|
| + // Leave a clue about what went wrong so that it can be (at least) picked
|
| + // up by a PLOG entry.
|
| + ::SetLastError(last_error);
|
| + }
|
| +
|
| + return ret;
|
| +}
|
| +
|
| +bool CopyFileUnsafe(const FilePath& from_path, const FilePath& to_path) {
|
| + ThreadRestrictions::AssertIOAllowed();
|
| +
|
| + // 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;
|
| + }
|
| + return (::CopyFile(from_path.value().c_str(), to_path.value().c_str(),
|
| + false) != 0);
|
| +}
|
| +
|
| +bool CopyAndDeleteDirectory(const FilePath& from_path,
|
| + const FilePath& to_path) {
|
| + ThreadRestrictions::AssertIOAllowed();
|
| + if (CopyDirectory(from_path, to_path, true)) {
|
| + if (Delete(from_path, true))
|
| + return true;
|
| +
|
| + // Like Move, this function is not transactional, so we just
|
| + // leave the copied bits behind if deleting from_path fails.
|
| + // If to_path exists previously then we have already overwritten
|
| + // it by now, we don't get better off by deleting the new bits.
|
| + }
|
| + return false;
|
| +}
|
| +
|
| +} // namespace internal
|
| +} // namespace base
|
|
|