OLD | NEW |
(Empty) | |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #include "content/browser/download/base_file.h" |
| 6 |
| 7 #include <windows.h> |
| 8 #include <shellapi.h> |
| 9 |
| 10 #include "base/threading/thread_restrictions.h" |
| 11 #include "base/utf_string_conversions.h" |
| 12 #include "content/browser/download/download_interrupt_reasons_impl.h" |
| 13 #include "content/browser/safe_util_win.h" |
| 14 #include "content/public/browser/browser_thread.h" |
| 15 |
| 16 namespace { |
| 17 |
| 18 // Maps the result of a call to |SHFileOperation()| onto a |
| 19 // |content::DownloadInterruptReason|. |
| 20 // |
| 21 // These return codes are *old* (as in, DOS era), and specific to |
| 22 // |SHFileOperation()|. |
| 23 // They do not appear in any windows header. |
| 24 // |
| 25 // See http://msdn.microsoft.com/en-us/library/bb762164(VS.85).aspx. |
| 26 content::DownloadInterruptReason MapShFileOperationCodes(int code) { |
| 27 // Check these pre-Win32 error codes first, then check for matches |
| 28 // in Winerror.h. |
| 29 |
| 30 switch (code) { |
| 31 // The source and destination files are the same file. |
| 32 // DE_SAMEFILE == 0x71 |
| 33 case 0x71: return content::DOWNLOAD_INTERRUPT_REASON_FILE_FAILED; |
| 34 |
| 35 // The operation was canceled by the user, or silently canceled if the |
| 36 // appropriate flags were supplied to SHFileOperation. |
| 37 // DE_OPCANCELLED == 0x75 |
| 38 case 0x75: return content::DOWNLOAD_INTERRUPT_REASON_FILE_FAILED; |
| 39 |
| 40 // Security settings denied access to the source. |
| 41 // DE_ACCESSDENIEDSRC == 0x78 |
| 42 case 0x78: return content::DOWNLOAD_INTERRUPT_REASON_FILE_ACCESS_DENIED; |
| 43 |
| 44 // The source or destination path exceeded or would exceed MAX_PATH. |
| 45 // DE_PATHTOODEEP == 0x79 |
| 46 case 0x79: return content::DOWNLOAD_INTERRUPT_REASON_FILE_NAME_TOO_LONG; |
| 47 |
| 48 // The path in the source or destination or both was invalid. |
| 49 // DE_INVALIDFILES == 0x7C |
| 50 case 0x7C: return content::DOWNLOAD_INTERRUPT_REASON_FILE_FAILED; |
| 51 |
| 52 // The destination path is an existing file. |
| 53 // DE_FLDDESTISFILE == 0x7E |
| 54 case 0x7E: return content::DOWNLOAD_INTERRUPT_REASON_FILE_FAILED; |
| 55 |
| 56 // The destination path is an existing folder. |
| 57 // DE_FILEDESTISFLD == 0x80 |
| 58 case 0x80: return content::DOWNLOAD_INTERRUPT_REASON_FILE_FAILED; |
| 59 |
| 60 // The name of the file exceeds MAX_PATH. |
| 61 // DE_FILENAMETOOLONG == 0x81 |
| 62 case 0x81: return content::DOWNLOAD_INTERRUPT_REASON_FILE_NAME_TOO_LONG; |
| 63 |
| 64 // The destination is a read-only CD-ROM, possibly unformatted. |
| 65 // DE_DEST_IS_CDROM == 0x82 |
| 66 case 0x82: return content::DOWNLOAD_INTERRUPT_REASON_FILE_ACCESS_DENIED; |
| 67 |
| 68 // The destination is a read-only DVD, possibly unformatted. |
| 69 // DE_DEST_IS_DVD == 0x83 |
| 70 case 0x83: return content::DOWNLOAD_INTERRUPT_REASON_FILE_ACCESS_DENIED; |
| 71 |
| 72 // The destination is a writable CD-ROM, possibly unformatted. |
| 73 // DE_DEST_IS_CDRECORD == 0x84 |
| 74 case 0x84: return content::DOWNLOAD_INTERRUPT_REASON_FILE_ACCESS_DENIED; |
| 75 |
| 76 // The file involved in the operation is too large for the destination |
| 77 // media or file system. |
| 78 // DE_FILE_TOO_LARGE == 0x85 |
| 79 case 0x85: return content::DOWNLOAD_INTERRUPT_REASON_FILE_TOO_LARGE; |
| 80 |
| 81 // The source is a read-only CD-ROM, possibly unformatted. |
| 82 // DE_SRC_IS_CDROM == 0x86 |
| 83 case 0x86: return content::DOWNLOAD_INTERRUPT_REASON_FILE_ACCESS_DENIED; |
| 84 |
| 85 // The source is a read-only DVD, possibly unformatted. |
| 86 // DE_SRC_IS_DVD == 0x87 |
| 87 case 0x87: return content::DOWNLOAD_INTERRUPT_REASON_FILE_ACCESS_DENIED; |
| 88 |
| 89 // The source is a writable CD-ROM, possibly unformatted. |
| 90 // DE_SRC_IS_CDRECORD == 0x88 |
| 91 case 0x88: return content::DOWNLOAD_INTERRUPT_REASON_FILE_ACCESS_DENIED; |
| 92 |
| 93 // MAX_PATH was exceeded during the operation. |
| 94 // DE_ERROR_MAX == 0xB7 |
| 95 case 0xB7: return content::DOWNLOAD_INTERRUPT_REASON_FILE_NAME_TOO_LONG; |
| 96 |
| 97 // An unspecified error occurred on the destination. |
| 98 // XE_ERRORONDEST == 0x10000 |
| 99 case 0x10000: return content::DOWNLOAD_INTERRUPT_REASON_FILE_FAILED; |
| 100 |
| 101 // Multiple file paths were specified in the source buffer, but only one |
| 102 // destination file path. |
| 103 // DE_MANYSRC1DEST == 0x72 |
| 104 case 0x72: return content::DOWNLOAD_INTERRUPT_REASON_FILE_FAILED; |
| 105 |
| 106 // Rename operation was specified but the destination path is |
| 107 // a different directory. Use the move operation instead. |
| 108 // DE_DIFFDIR == 0x73 |
| 109 case 0x73: return content::DOWNLOAD_INTERRUPT_REASON_FILE_FAILED; |
| 110 |
| 111 // The source is a root directory, which cannot be moved or renamed. |
| 112 // DE_ROOTDIR == 0x74 |
| 113 case 0x74: return content::DOWNLOAD_INTERRUPT_REASON_FILE_FAILED; |
| 114 |
| 115 // The destination is a subtree of the source. |
| 116 // DE_DESTSUBTREE == 0x76 |
| 117 case 0x76: return content::DOWNLOAD_INTERRUPT_REASON_FILE_FAILED; |
| 118 |
| 119 // The operation involved multiple destination paths, |
| 120 // which can fail in the case of a move operation. |
| 121 // DE_MANYDEST == 0x7A |
| 122 case 0x7A: return content::DOWNLOAD_INTERRUPT_REASON_FILE_FAILED; |
| 123 |
| 124 // The source and destination have the same parent folder. |
| 125 // DE_DESTSAMETREE == 0x7D |
| 126 case 0x7D: return content::DOWNLOAD_INTERRUPT_REASON_FILE_FAILED; |
| 127 |
| 128 // An unknown error occurred. This is typically due to an invalid path in |
| 129 // the source or destination. This error does not occur on Windows Vista |
| 130 // and later. |
| 131 // DE_UNKNOWN_ERROR == 0x402 |
| 132 case 0x402: return content::DOWNLOAD_INTERRUPT_REASON_FILE_FAILED; |
| 133 |
| 134 // Destination is a root directory and cannot be renamed. |
| 135 // DE_ROOTDIR | ERRORONDEST == 0x10074 |
| 136 case 0x10074: return content::DOWNLOAD_INTERRUPT_REASON_FILE_FAILED; |
| 137 } |
| 138 |
| 139 // If not one of the above codes, it should be a standard Windows error code. |
| 140 return content::ConvertNetErrorToInterruptReason( |
| 141 net::MapSystemError(code), content::DOWNLOAD_INTERRUPT_FROM_DISK); |
| 142 } |
| 143 |
| 144 } // namespace |
| 145 |
| 146 // Renames a file using the SHFileOperation API to ensure that the target file |
| 147 // gets the correct default security descriptor in the new path. |
| 148 // Returns a network error, or net::OK for success. |
| 149 content::DownloadInterruptReason BaseFile::MoveFileAndAdjustPermissions( |
| 150 const FilePath& new_path) { |
| 151 base::ThreadRestrictions::AssertIOAllowed(); |
| 152 |
| 153 // The parameters to SHFileOperation must be terminated with 2 NULL chars. |
| 154 FilePath::StringType source = full_path_.value(); |
| 155 FilePath::StringType target = new_path.value(); |
| 156 |
| 157 source.append(1, L'\0'); |
| 158 target.append(1, L'\0'); |
| 159 |
| 160 SHFILEOPSTRUCT move_info = {0}; |
| 161 move_info.wFunc = FO_MOVE; |
| 162 move_info.pFrom = source.c_str(); |
| 163 move_info.pTo = target.c_str(); |
| 164 move_info.fFlags = FOF_SILENT | FOF_NOCONFIRMATION | FOF_NOERRORUI | |
| 165 FOF_NOCONFIRMMKDIR | FOF_NOCOPYSECURITYATTRIBS; |
| 166 |
| 167 int result = SHFileOperation(&move_info); |
| 168 content::DownloadInterruptReason interrupt_reason = |
| 169 content::DOWNLOAD_INTERRUPT_REASON_NONE; |
| 170 |
| 171 if (result == 0 && move_info.fAnyOperationsAborted) |
| 172 interrupt_reason = content::DOWNLOAD_INTERRUPT_REASON_FILE_FAILED; |
| 173 else if (result != 0) |
| 174 interrupt_reason = MapShFileOperationCodes(result); |
| 175 |
| 176 if (interrupt_reason != content::DOWNLOAD_INTERRUPT_REASON_NONE) |
| 177 return LogInterruptReason("SHFileOperation", result, interrupt_reason); |
| 178 return interrupt_reason; |
| 179 } |
| 180 |
| 181 void BaseFile::AnnotateWithSourceInformation() { |
| 182 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE)); |
| 183 DCHECK(!detached_); |
| 184 |
| 185 // Sets the Zone to tell Windows that this file comes from the internet. |
| 186 // We ignore the return value because a failure is not fatal. |
| 187 win_util::SetInternetZoneIdentifier(full_path_, |
| 188 UTF8ToWide(source_url_.spec())); |
| 189 } |
OLD | NEW |