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 #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.
| |
31 case value: return content::DOWNLOAD_INTERRUPT_REASON_##mapping | |
32 | |
33 switch (code) { | |
34 // The source and destination files are the same file. | |
35 SHFILE_TO_REASON(DE_SAMEFILE, 0x71, FILE_FAILED); | |
36 | |
37 // The operation was canceled by the user, or silently canceled if the | |
38 // appropriate flags were supplied to SHFileOperation. | |
39 SHFILE_TO_REASON(DE_OPCANCELLED, 0x75, FILE_FAILED); | |
40 | |
41 // Security settings denied access to the source. | |
42 SHFILE_TO_REASON(DE_ACCESSDENIEDSRC, 0x78, FILE_ACCESS_DENIED); | |
43 | |
44 // The source or destination path exceeded or would exceed MAX_PATH. | |
45 SHFILE_TO_REASON(DE_PATHTOODEEP, 0x79, FILE_NAME_TOO_LONG); | |
46 | |
47 // The path in the source or destination or both was invalid. | |
48 SHFILE_TO_REASON(DE_INVALIDFILES, 0x7C, FILE_FAILED); | |
49 | |
50 // The destination path is an existing file. | |
51 SHFILE_TO_REASON(DE_FLDDESTISFILE, 0x7E, FILE_FAILED); | |
52 | |
53 // The destination path is an existing folder. | |
54 SHFILE_TO_REASON(DE_FILEDESTISFLD, 0x80, FILE_FAILED); | |
55 | |
56 // The name of the file exceeds MAX_PATH. | |
57 SHFILE_TO_REASON(DE_FILENAMETOOLONG, 0x81, FILE_NAME_TOO_LONG); | |
58 | |
59 // The destination is a read-only CD-ROM, possibly unformatted. | |
60 SHFILE_TO_REASON(DE_DEST_IS_CDROM, 0x82, FILE_ACCESS_DENIED); | |
61 | |
62 // The destination is a read-only DVD, possibly unformatted. | |
63 SHFILE_TO_REASON(DE_DEST_IS_DVD, 0x83, FILE_ACCESS_DENIED); | |
64 | |
65 // The destination is a writable CD-ROM, possibly unformatted. | |
66 SHFILE_TO_REASON(DE_DEST_IS_CDRECORD, 0x84, FILE_ACCESS_DENIED); | |
67 | |
68 // The file involved in the operation is too large for the destination | |
69 // media or file system. | |
70 SHFILE_TO_REASON(DE_FILE_TOO_LARGE, 0x85, FILE_TOO_LARGE); | |
71 | |
72 // The source is a read-only CD-ROM, possibly unformatted. | |
73 SHFILE_TO_REASON(DE_SRC_IS_CDROM, 0x86, FILE_ACCESS_DENIED); | |
74 | |
75 // The source is a read-only DVD, possibly unformatted. | |
76 SHFILE_TO_REASON(DE_SRC_IS_DVD, 0x87, FILE_ACCESS_DENIED); | |
77 | |
78 // The source is a writable CD-ROM, possibly unformatted. | |
79 SHFILE_TO_REASON(DE_SRC_IS_CDRECORD, 0x88, FILE_ACCESS_DENIED); | |
80 | |
81 // MAX_PATH was exceeded during the operation. | |
82 SHFILE_TO_REASON(DE_ERROR_MAX, 0xB7, FILE_NAME_TOO_LONG); | |
83 | |
84 // An unspecified error occurred on the destination. | |
85 SHFILE_TO_REASON(XE_ERRORONDEST, 0x10000, FILE_FAILED); | |
86 | |
87 // Multiple file paths were specified in the source buffer, but only one | |
88 // destination file path. | |
89 SHFILE_TO_REASON(DE_MANYSRC1DEST, 0x72, FILE_FAILED); | |
90 | |
91 // Rename operation was specified but the destination path is | |
92 // a different directory. Use the move operation instead. | |
93 SHFILE_TO_REASON(DE_DIFFDIR, 0x73, FILE_FAILED); | |
94 | |
95 // The source is a root directory, which cannot be moved or renamed. | |
96 SHFILE_TO_REASON(DE_ROOTDIR, 0x74, FILE_FAILED); | |
97 | |
98 // The destination is a subtree of the source. | |
99 SHFILE_TO_REASON(DE_DESTSUBTREE, 0x76, FILE_FAILED); | |
100 | |
101 // The operation involved multiple destination paths, | |
102 // which can fail in the case of a move operation. | |
103 SHFILE_TO_REASON(DE_MANYDEST, 0x7A, FILE_FAILED); | |
104 | |
105 // The source and destination have the same parent folder. | |
106 SHFILE_TO_REASON(DE_DESTSAMETREE, 0x7D, FILE_FAILED); | |
107 | |
108 // An unknown error occurred. This is typically due to an invalid path in | |
109 // the source or destination. This error does not occur on Windows Vista | |
110 // and later. | |
111 SHFILE_TO_REASON(DE_UNKNOWN_ERROR, 0x402, FILE_FAILED); | |
112 | |
113 // Destination is a root directory and cannot be renamed. | |
114 SHFILE_TO_REASON(DE_ROOTDIR | ERRORONDEST, 0x10074, FILE_FAILED); | |
115 } | |
116 | |
117 #undef SHFILE_TO_REASON | |
118 | |
119 // If not one of the above codes, it should be a standard Windows error code. | |
120 return content::ConvertNetErrorToInterruptReason( | |
121 net::MapSystemError(code), content::DOWNLOAD_INTERRUPT_FROM_DISK); | |
122 } | |
123 | |
124 } // namespace | |
125 | |
126 // Renames a file using the SHFileOperation API to ensure that the target file | |
127 // gets the correct default security descriptor in the new path. | |
128 // Returns a network error, or net::OK for success. | |
129 content::DownloadInterruptReason BaseFile::MoveFileAndAdjustPermissions( | |
130 const FilePath& new_path) { | |
131 base::ThreadRestrictions::AssertIOAllowed(); | |
132 | |
133 // The parameters to SHFileOperation must be terminated with 2 NULL chars. | |
134 FilePath::StringType source = full_path_.value(); | |
135 FilePath::StringType target = new_path.value(); | |
136 | |
137 source.append(1, L'\0'); | |
138 target.append(1, L'\0'); | |
139 | |
140 SHFILEOPSTRUCT move_info = {0}; | |
141 move_info.wFunc = FO_MOVE; | |
142 move_info.pFrom = source.c_str(); | |
143 move_info.pTo = target.c_str(); | |
144 move_info.fFlags = FOF_SILENT | FOF_NOCONFIRMATION | FOF_NOERRORUI | | |
145 FOF_NOCONFIRMMKDIR | FOF_NOCOPYSECURITYATTRIBS; | |
146 | |
147 int result = SHFileOperation(&move_info); | |
148 content::DownloadInterruptReason interrupt_reason = | |
149 content::DOWNLOAD_INTERRUPT_REASON_NONE; | |
150 | |
151 if (result == 0 && move_info.fAnyOperationsAborted) | |
152 interrupt_reason = content::DOWNLOAD_INTERRUPT_REASON_FILE_FAILED; | |
153 else if (result != 0) | |
154 interrupt_reason = MapShFileOperationCodes(result); | |
155 | |
156 if (interrupt_reason != content::DOWNLOAD_INTERRUPT_REASON_NONE) | |
157 return LogInterruptReason("SHFileOperation", result, interrupt_reason); | |
158 return interrupt_reason; | |
159 } | |
160 | |
161 void BaseFile::AnnotateWithSourceInformation() { | |
162 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE)); | |
163 DCHECK(!detached_); | |
164 | |
165 // Sets the Zone to tell Windows that this file comes from the internet. | |
166 // We ignore the return value because a failure is not fatal. | |
167 win_util::SetInternetZoneIdentifier(full_path_, | |
168 UTF8ToWide(source_url_.spec())); | |
169 } | |
OLD | NEW |