Chromium Code Reviews| Index: content/browser/download/base_file_win.cc |
| diff --git a/content/browser/download/base_file_win.cc b/content/browser/download/base_file_win.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..8d4f4353ae6ab8e1d0318d561f5a8e79da30a29f |
| --- /dev/null |
| +++ b/content/browser/download/base_file_win.cc |
| @@ -0,0 +1,169 @@ |
| +// Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| +// Use of this source code is governed by a BSD-style license that can be |
| +// found in the LICENSE file. |
| + |
| +#include "content/browser/download/base_file.h" |
| + |
| +#include <windows.h> |
| +#include <shellapi.h> |
| + |
| +#include "base/threading/thread_restrictions.h" |
| +#include "base/utf_string_conversions.h" |
| +#include "content/browser/download/download_interrupt_reasons_impl.h" |
| +#include "content/browser/safe_util_win.h" |
| +#include "content/public/browser/browser_thread.h" |
| + |
| +namespace { |
| + |
| +// Maps the result of a call to |SHFileOperation()| onto a |
| +// |content::DownloadInterruptReason|. |
| +// |
| +// These return codes are *old* (as in, DOS era), and specific to |
| +// |SHFileOperation()|. |
| +// They do not appear in any windows header. |
| +// |
| +// See http://msdn.microsoft.com/en-us/library/bb762164(VS.85).aspx. |
| +content::DownloadInterruptReason MapShFileOperationCodes(int code) { |
| + // Check these pre-Win32 error codes first, then check for matches |
| + // in Winerror.h. |
| + |
| +#define SHFILE_TO_REASON(symbol, value, mapping) \ |
|
jam
2012/10/24 20:49:00
the style guide says to avoid using macros to gene
asanka
2012/10/24 21:40:44
Done.
|
| + case value: return content::DOWNLOAD_INTERRUPT_REASON_##mapping |
| + |
| + switch (code) { |
| + // The source and destination files are the same file. |
| + SHFILE_TO_REASON(DE_SAMEFILE, 0x71, FILE_FAILED); |
| + |
| + // The operation was canceled by the user, or silently canceled if the |
| + // appropriate flags were supplied to SHFileOperation. |
| + SHFILE_TO_REASON(DE_OPCANCELLED, 0x75, FILE_FAILED); |
| + |
| + // Security settings denied access to the source. |
| + SHFILE_TO_REASON(DE_ACCESSDENIEDSRC, 0x78, FILE_ACCESS_DENIED); |
| + |
| + // The source or destination path exceeded or would exceed MAX_PATH. |
| + SHFILE_TO_REASON(DE_PATHTOODEEP, 0x79, FILE_NAME_TOO_LONG); |
| + |
| + // The path in the source or destination or both was invalid. |
| + SHFILE_TO_REASON(DE_INVALIDFILES, 0x7C, FILE_FAILED); |
| + |
| + // The destination path is an existing file. |
| + SHFILE_TO_REASON(DE_FLDDESTISFILE, 0x7E, FILE_FAILED); |
| + |
| + // The destination path is an existing folder. |
| + SHFILE_TO_REASON(DE_FILEDESTISFLD, 0x80, FILE_FAILED); |
| + |
| + // The name of the file exceeds MAX_PATH. |
| + SHFILE_TO_REASON(DE_FILENAMETOOLONG, 0x81, FILE_NAME_TOO_LONG); |
| + |
| + // The destination is a read-only CD-ROM, possibly unformatted. |
| + SHFILE_TO_REASON(DE_DEST_IS_CDROM, 0x82, FILE_ACCESS_DENIED); |
| + |
| + // The destination is a read-only DVD, possibly unformatted. |
| + SHFILE_TO_REASON(DE_DEST_IS_DVD, 0x83, FILE_ACCESS_DENIED); |
| + |
| + // The destination is a writable CD-ROM, possibly unformatted. |
| + SHFILE_TO_REASON(DE_DEST_IS_CDRECORD, 0x84, FILE_ACCESS_DENIED); |
| + |
| + // The file involved in the operation is too large for the destination |
| + // media or file system. |
| + SHFILE_TO_REASON(DE_FILE_TOO_LARGE, 0x85, FILE_TOO_LARGE); |
| + |
| + // The source is a read-only CD-ROM, possibly unformatted. |
| + SHFILE_TO_REASON(DE_SRC_IS_CDROM, 0x86, FILE_ACCESS_DENIED); |
| + |
| + // The source is a read-only DVD, possibly unformatted. |
| + SHFILE_TO_REASON(DE_SRC_IS_DVD, 0x87, FILE_ACCESS_DENIED); |
| + |
| + // The source is a writable CD-ROM, possibly unformatted. |
| + SHFILE_TO_REASON(DE_SRC_IS_CDRECORD, 0x88, FILE_ACCESS_DENIED); |
| + |
| + // MAX_PATH was exceeded during the operation. |
| + SHFILE_TO_REASON(DE_ERROR_MAX, 0xB7, FILE_NAME_TOO_LONG); |
| + |
| + // An unspecified error occurred on the destination. |
| + SHFILE_TO_REASON(XE_ERRORONDEST, 0x10000, FILE_FAILED); |
| + |
| + // Multiple file paths were specified in the source buffer, but only one |
| + // destination file path. |
| + SHFILE_TO_REASON(DE_MANYSRC1DEST, 0x72, FILE_FAILED); |
| + |
| + // Rename operation was specified but the destination path is |
| + // a different directory. Use the move operation instead. |
| + SHFILE_TO_REASON(DE_DIFFDIR, 0x73, FILE_FAILED); |
| + |
| + // The source is a root directory, which cannot be moved or renamed. |
| + SHFILE_TO_REASON(DE_ROOTDIR, 0x74, FILE_FAILED); |
| + |
| + // The destination is a subtree of the source. |
| + SHFILE_TO_REASON(DE_DESTSUBTREE, 0x76, FILE_FAILED); |
| + |
| + // The operation involved multiple destination paths, |
| + // which can fail in the case of a move operation. |
| + SHFILE_TO_REASON(DE_MANYDEST, 0x7A, FILE_FAILED); |
| + |
| + // The source and destination have the same parent folder. |
| + SHFILE_TO_REASON(DE_DESTSAMETREE, 0x7D, FILE_FAILED); |
| + |
| + // An unknown error occurred. This is typically due to an invalid path in |
| + // the source or destination. This error does not occur on Windows Vista |
| + // and later. |
| + SHFILE_TO_REASON(DE_UNKNOWN_ERROR, 0x402, FILE_FAILED); |
| + |
| + // Destination is a root directory and cannot be renamed. |
| + SHFILE_TO_REASON(DE_ROOTDIR | ERRORONDEST, 0x10074, FILE_FAILED); |
| + } |
| + |
| +#undef SHFILE_TO_REASON |
| + |
| + // If not one of the above codes, it should be a standard Windows error code. |
| + return content::ConvertNetErrorToInterruptReason( |
| + net::MapSystemError(code), content::DOWNLOAD_INTERRUPT_FROM_DISK); |
| +} |
| + |
| +} // namespace |
| + |
| +// Renames a file using the SHFileOperation API to ensure that the target file |
| +// gets the correct default security descriptor in the new path. |
| +// Returns a network error, or net::OK for success. |
| +content::DownloadInterruptReason BaseFile::MoveFileAndAdjustPermissions( |
| + const FilePath& new_path) { |
| + base::ThreadRestrictions::AssertIOAllowed(); |
| + |
| + // The parameters to SHFileOperation must be terminated with 2 NULL chars. |
| + FilePath::StringType source = full_path_.value(); |
| + FilePath::StringType target = new_path.value(); |
| + |
| + source.append(1, L'\0'); |
| + target.append(1, L'\0'); |
| + |
| + SHFILEOPSTRUCT move_info = {0}; |
| + move_info.wFunc = FO_MOVE; |
| + move_info.pFrom = source.c_str(); |
| + move_info.pTo = target.c_str(); |
| + move_info.fFlags = FOF_SILENT | FOF_NOCONFIRMATION | FOF_NOERRORUI | |
| + FOF_NOCONFIRMMKDIR | FOF_NOCOPYSECURITYATTRIBS; |
| + |
| + int result = SHFileOperation(&move_info); |
| + content::DownloadInterruptReason interrupt_reason = |
| + content::DOWNLOAD_INTERRUPT_REASON_NONE; |
| + |
| + if (result == 0 && move_info.fAnyOperationsAborted) |
| + interrupt_reason = content::DOWNLOAD_INTERRUPT_REASON_FILE_FAILED; |
| + else if (result != 0) |
| + interrupt_reason = MapShFileOperationCodes(result); |
| + |
| + if (interrupt_reason != content::DOWNLOAD_INTERRUPT_REASON_NONE) |
| + return LogInterruptReason("SHFileOperation", result, interrupt_reason); |
| + return interrupt_reason; |
| +} |
| + |
| +void BaseFile::AnnotateWithSourceInformation() { |
| + DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE)); |
| + DCHECK(!detached_); |
| + |
| + // Sets the Zone to tell Windows that this file comes from the internet. |
| + // We ignore the return value because a failure is not fatal. |
| + win_util::SetInternetZoneIdentifier(full_path_, |
| + UTF8ToWide(source_url_.spec())); |
| +} |