Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(391)

Side by Side Diff: content/browser/download/base_file.cc

Issue 11238044: Refactor BaseFile methods to return a DownloadInterruptReason instead of a net::Error. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 8 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "content/browser/download/base_file.h" 5 #include "content/browser/download/base_file.h"
6 6
7 #include "base/bind.h" 7 #include "base/bind.h"
8 #include "base/file_util.h" 8 #include "base/file_util.h"
9 #include "base/format_macros.h" 9 #include "base/format_macros.h"
10 #include "base/logging.h" 10 #include "base/logging.h"
11 #include "base/pickle.h" 11 #include "base/pickle.h"
12 #include "base/stringprintf.h" 12 #include "base/stringprintf.h"
13 #include "base/threading/thread_restrictions.h" 13 #include "base/threading/thread_restrictions.h"
14 #include "base/utf_string_conversions.h" 14 #include "content/browser/download/download_interrupt_reasons_impl.h"
15 #include "content/browser/download/download_net_log_parameters.h" 15 #include "content/browser/download/download_net_log_parameters.h"
16 #include "content/browser/download/download_stats.h" 16 #include "content/browser/download/download_stats.h"
17 #include "content/public/browser/browser_thread.h" 17 #include "content/public/browser/browser_thread.h"
18 #include "content/public/browser/content_browser_client.h" 18 #include "content/public/browser/content_browser_client.h"
19 #include "crypto/secure_hash.h" 19 #include "crypto/secure_hash.h"
20 #include "net/base/file_stream.h" 20 #include "net/base/file_stream.h"
21 #include "net/base/net_errors.h" 21 #include "net/base/net_errors.h"
22 22
23 #if defined(OS_WIN)
24 #include <windows.h>
25 #include <shellapi.h>
26
27 #include "content/browser/safe_util_win.h"
28 #elif defined(OS_MACOSX)
29 #include "content/browser/download/file_metadata_mac.h"
30 #elif defined(OS_LINUX)
31 #include "content/browser/download/file_metadata_linux.h"
32 #endif
33
34 using content::BrowserThread; 23 using content::BrowserThread;
35 24
36 namespace {
37
38 #define LOG_ERROR(o, e) \
39 LogError(__FILE__, __LINE__, __FUNCTION__, bound_net_log_, o, e)
40
41 // Logs the value and passes error on through, converting to a |net::Error|.
42 // Returns |ERR_UNEXPECTED| if the value is not in the enum.
43 net::Error LogError(const char* file,
44 int line,
45 const char* func,
46 const net::BoundNetLog& bound_net_log,
47 const char* operation,
48 int error) {
49 const char* err_string = "";
50 net::Error net_error = net::OK;
51
52 #define NET_ERROR(label, value) \
53 case net::ERR_##label: \
54 err_string = #label; \
55 net_error = net::ERR_##label; \
56 break;
57
58 switch (error) {
59 case net::OK:
60 return net::OK;
61
62 #include "net/base/net_error_list.h"
63
64 default:
65 err_string = "Unexpected enum value";
66 net_error = net::ERR_UNEXPECTED;
67 break;
68 }
69
70 #undef NET_ERROR
71
72 VLOG(1) << " " << func << "(): " << operation
73 << "() returned error " << error << " (" << err_string << ")";
74
75 bound_net_log.AddEvent(
76 net::NetLog::TYPE_DOWNLOAD_FILE_ERROR,
77 base::Bind(&download_net_logs::FileErrorCallback, operation, net_error));
78
79 return net_error;
80 }
81
82 #if defined(OS_WIN)
83
84 #define SHFILE_TO_NET_ERROR(symbol, value, mapping, description) \
85 case value: return net::ERR_##mapping;
86
87 // Maps the result of a call to |SHFileOperation()| onto a |net::Error|.
88 //
89 // These return codes are *old* (as in, DOS era), and specific to
90 // |SHFileOperation()|.
91 // They do not appear in any windows header.
92 //
93 // See http://msdn.microsoft.com/en-us/library/bb762164(VS.85).aspx.
94 net::Error MapShFileOperationCodes(int code) {
95 // Check these pre-Win32 error codes first, then check for matches
96 // in Winerror.h.
97
98 switch (code) {
99 // Error Code, Value, Platform Error Mapping, Meaning
100 SHFILE_TO_NET_ERROR(DE_SAMEFILE, 0x71, FILE_EXISTS,
101 "The source and destination files are the same file.")
102 SHFILE_TO_NET_ERROR(DE_OPCANCELLED, 0x75, ABORTED,
103 "The operation was canceled by the user, or silently canceled if "
104 "the appropriate flags were supplied to SHFileOperation.")
105 SHFILE_TO_NET_ERROR(DE_ACCESSDENIEDSRC, 0x78, ACCESS_DENIED,
106 "Security settings denied access to the source.")
107 SHFILE_TO_NET_ERROR(DE_PATHTOODEEP, 0x79, FILE_PATH_TOO_LONG,
108 "The source or destination path exceeded or would exceed MAX_PATH.")
109 SHFILE_TO_NET_ERROR(DE_INVALIDFILES, 0x7C, FILE_NOT_FOUND,
110 "The path in the source or destination or both was invalid.")
111 SHFILE_TO_NET_ERROR(DE_FLDDESTISFILE, 0x7E, FILE_EXISTS,
112 "The destination path is an existing file.")
113 SHFILE_TO_NET_ERROR(DE_FILEDESTISFLD, 0x80, FILE_EXISTS,
114 "The destination path is an existing folder.")
115 SHFILE_TO_NET_ERROR(DE_FILENAMETOOLONG, 0x81, FILE_PATH_TOO_LONG,
116 "The name of the file exceeds MAX_PATH.")
117 SHFILE_TO_NET_ERROR(DE_DEST_IS_CDROM, 0x82, ACCESS_DENIED,
118 "The destination is a read-only CD-ROM, possibly unformatted.")
119 SHFILE_TO_NET_ERROR(DE_DEST_IS_DVD, 0x83, ACCESS_DENIED,
120 "The destination is a read-only DVD, possibly unformatted.")
121 SHFILE_TO_NET_ERROR(DE_DEST_IS_CDRECORD, 0x84, ACCESS_DENIED,
122 "The destination is a writable CD-ROM, possibly unformatted.")
123 SHFILE_TO_NET_ERROR(DE_FILE_TOO_LARGE, 0x85, FILE_TOO_BIG,
124 "The file involved in the operation is too large for the destination "
125 "media or file system.")
126 SHFILE_TO_NET_ERROR(DE_SRC_IS_CDROM, 0x86, ACCESS_DENIED,
127 "The source is a read-only CD-ROM, possibly unformatted.")
128 SHFILE_TO_NET_ERROR(DE_SRC_IS_DVD, 0x87, ACCESS_DENIED,
129 "The source is a read-only DVD, possibly unformatted.")
130 SHFILE_TO_NET_ERROR(DE_SRC_IS_CDRECORD, 0x88, ACCESS_DENIED,
131 "The source is a writable CD-ROM, possibly unformatted.")
132 SHFILE_TO_NET_ERROR(DE_ERROR_MAX, 0xB7, FILE_PATH_TOO_LONG,
133 "MAX_PATH was exceeded during the operation.")
134 SHFILE_TO_NET_ERROR(XE_ERRORONDEST, 0x10000, UNEXPECTED,
135 "An unspecified error occurred on the destination.")
136
137 // These are not expected to occur for in our usage.
138 SHFILE_TO_NET_ERROR(DE_MANYSRC1DEST, 0x72, FAILED,
139 "Multiple file paths were specified in the source buffer, "
140 "but only one destination file path.")
141 SHFILE_TO_NET_ERROR(DE_DIFFDIR, 0x73, FAILED,
142 "Rename operation was specified but the destination path is "
143 "a different directory. Use the move operation instead.")
144 SHFILE_TO_NET_ERROR(DE_ROOTDIR, 0x74, FAILED,
145 "The source is a root directory, which cannot be moved or renamed.")
146 SHFILE_TO_NET_ERROR(DE_DESTSUBTREE, 0x76, FAILED,
147 "The destination is a subtree of the source.")
148 SHFILE_TO_NET_ERROR(DE_MANYDEST, 0x7A, FAILED,
149 "The operation involved multiple destination paths, "
150 "which can fail in the case of a move operation.")
151 SHFILE_TO_NET_ERROR(DE_DESTSAMETREE, 0x7D, FAILED,
152 "The source and destination have the same parent folder.")
153 SHFILE_TO_NET_ERROR(DE_UNKNOWN_ERROR, 0x402, FAILED,
154 "An unknown error occurred. "
155 "This is typically due to an invalid path in the source or destination."
156 " This error does not occur on Windows Vista and later.")
157 SHFILE_TO_NET_ERROR(DE_ROOTDIR | ERRORONDEST, 0x10074, FAILED,
158 "Destination is a root directory and cannot be renamed.")
159 default:
160 break;
161 }
162
163 // If not one of the above codes, it should be a standard Windows error code.
164 return static_cast<net::Error>(net::MapSystemError(code));
165 }
166
167 #undef SHFILE_TO_NET_ERROR
168
169 // Renames a file using the SHFileOperation API to ensure that the target file
170 // gets the correct default security descriptor in the new path.
171 // Returns a network error, or net::OK for success.
172 net::Error RenameFileAndResetSecurityDescriptor(
173 const FilePath& source_file_path,
174 const FilePath& target_file_path) {
175 base::ThreadRestrictions::AssertIOAllowed();
176
177 // The parameters to SHFileOperation must be terminated with 2 NULL chars.
178 std::wstring source = source_file_path.value();
179 std::wstring target = target_file_path.value();
180
181 source.append(1, L'\0');
182 target.append(1, L'\0');
183
184 SHFILEOPSTRUCT move_info = {0};
185 move_info.wFunc = FO_MOVE;
186 move_info.pFrom = source.c_str();
187 move_info.pTo = target.c_str();
188 move_info.fFlags = FOF_SILENT | FOF_NOCONFIRMATION | FOF_NOERRORUI |
189 FOF_NOCONFIRMMKDIR | FOF_NOCOPYSECURITYATTRIBS;
190
191 int result = SHFileOperation(&move_info);
192
193 if (result == 0)
194 return (move_info.fAnyOperationsAborted) ? net::ERR_ABORTED : net::OK;
195
196 return MapShFileOperationCodes(result);
197 }
198
199 #endif
200
201 } // namespace
202
203 // This will initialize the entire array to zero. 25 // This will initialize the entire array to zero.
204 const unsigned char BaseFile::kEmptySha256Hash[] = { 0 }; 26 const unsigned char BaseFile::kEmptySha256Hash[] = { 0 };
205 27
206 BaseFile::BaseFile(const FilePath& full_path, 28 BaseFile::BaseFile(const FilePath& full_path,
207 const GURL& source_url, 29 const GURL& source_url,
208 const GURL& referrer_url, 30 const GURL& referrer_url,
209 int64 received_bytes, 31 int64 received_bytes,
210 bool calculate_hash, 32 bool calculate_hash,
211 const std::string& hash_state, 33 const std::string& hash_state,
212 scoped_ptr<net::FileStream> file_stream, 34 scoped_ptr<net::FileStream> file_stream,
(...skipping 19 matching lines...) Expand all
232 } 54 }
233 55
234 BaseFile::~BaseFile() { 56 BaseFile::~BaseFile() {
235 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 57 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
236 if (detached_) 58 if (detached_)
237 Close(); 59 Close();
238 else 60 else
239 Cancel(); // Will delete the file. 61 Cancel(); // Will delete the file.
240 } 62 }
241 63
242 net::Error BaseFile::Initialize(const FilePath& default_directory) { 64 content::DownloadInterruptReason BaseFile::Initialize(
65 const FilePath& default_directory) {
243 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 66 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
244 DCHECK(!detached_); 67 DCHECK(!detached_);
245 68
246 if (file_stream_.get()) { 69 if (file_stream_.get()) {
247 file_stream_->SetBoundNetLogSource(bound_net_log_); 70 file_stream_->SetBoundNetLogSource(bound_net_log_);
248 file_stream_->EnableErrorStatistics(); 71 file_stream_->EnableErrorStatistics();
249 } 72 }
250 73
251 if (full_path_.empty()) { 74 if (full_path_.empty()) {
252 FilePath initial_directory(default_directory); 75 FilePath initial_directory(default_directory);
253 FilePath temp_file; 76 FilePath temp_file;
254 if (initial_directory.empty()) { 77 if (initial_directory.empty()) {
255 initial_directory = 78 initial_directory =
256 content::GetContentClient()->browser()->GetDefaultDownloadDirectory(); 79 content::GetContentClient()->browser()->GetDefaultDownloadDirectory();
257 } 80 }
258 // |initial_directory| can still be empty if ContentBrowserClient returned 81 // |initial_directory| can still be empty if ContentBrowserClient returned
259 // an empty path for the downloads directory. 82 // an empty path for the downloads directory.
260 if ((initial_directory.empty() || 83 if ((initial_directory.empty() ||
261 !file_util::CreateTemporaryFileInDir(initial_directory, &temp_file)) && 84 !file_util::CreateTemporaryFileInDir(initial_directory, &temp_file)) &&
262 !file_util::CreateTemporaryFile(&temp_file)) { 85 !file_util::CreateTemporaryFile(&temp_file)) {
263 return LOG_ERROR("unable to create", net::ERR_FILE_NOT_FOUND); 86 return LogInterruptReason("Unable to create", 0,
87 content::DOWNLOAD_INTERRUPT_REASON_FILE_FAILED);
264 } 88 }
265 full_path_ = temp_file; 89 full_path_ = temp_file;
266 } 90 }
267 91
268 return Open(); 92 return Open();
269 } 93 }
270 94
271 net::Error BaseFile::AppendDataToFile(const char* data, size_t data_len) { 95 content::DownloadInterruptReason BaseFile::AppendDataToFile(const char* data,
96 size_t data_len) {
272 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 97 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
273 DCHECK(!detached_); 98 DCHECK(!detached_);
274 99
275 // NOTE(benwells): The above DCHECK won't be present in release builds, 100 // NOTE(benwells): The above DCHECK won't be present in release builds,
276 // so we log any occurences to see how common this error is in the wild. 101 // so we log any occurences to see how common this error is in the wild.
277 if (detached_) { 102 if (detached_) {
278 download_stats::RecordDownloadCount( 103 download_stats::RecordDownloadCount(
279 download_stats::APPEND_TO_DETACHED_FILE_COUNT); 104 download_stats::APPEND_TO_DETACHED_FILE_COUNT);
280 } 105 }
281 106
282 if (!file_stream_.get()) 107 if (!file_stream_.get())
283 return LOG_ERROR("get", net::ERR_INVALID_HANDLE); 108 return LogInterruptReason("No file stream on append", 0,
109 content::DOWNLOAD_INTERRUPT_REASON_FILE_FAILED);
284 110
285 // TODO(phajdan.jr): get rid of this check. 111 // TODO(phajdan.jr): get rid of this check.
286 if (data_len == 0) 112 if (data_len == 0)
287 return net::OK; 113 return content::DOWNLOAD_INTERRUPT_REASON_NONE;
288 114
289 // The Write call below is not guaranteed to write all the data. 115 // The Write call below is not guaranteed to write all the data.
290 size_t write_count = 0; 116 size_t write_count = 0;
291 size_t len = data_len; 117 size_t len = data_len;
292 const char* current_data = data; 118 const char* current_data = data;
293 while (len > 0) { 119 while (len > 0) {
294 write_count++; 120 write_count++;
295 int write_result = 121 int write_result =
296 file_stream_->WriteSync(current_data, len); 122 file_stream_->WriteSync(current_data, len);
297 DCHECK_NE(0, write_result); 123 DCHECK_NE(0, write_result);
298 124
299 // Check for errors. 125 // Check for errors.
300 if (static_cast<size_t>(write_result) != data_len) { 126 if (static_cast<size_t>(write_result) != data_len) {
301 // We should never get ERR_IO_PENDING, as the Write above is synchronous. 127 // We should never get ERR_IO_PENDING, as the Write above is synchronous.
302 DCHECK_NE(net::ERR_IO_PENDING, write_result); 128 DCHECK_NE(net::ERR_IO_PENDING, write_result);
303 129
304 // Report errors on file writes. 130 // Report errors on file writes.
305 if (write_result < 0) 131 if (write_result < 0)
306 return LOG_ERROR("Write", write_result); 132 return LogNetError("Write", static_cast<net::Error>(write_result));
307 } 133 }
308 134
309 // Update status. 135 // Update status.
310 size_t write_size = static_cast<size_t>(write_result); 136 size_t write_size = static_cast<size_t>(write_result);
311 DCHECK_LE(write_size, len); 137 DCHECK_LE(write_size, len);
312 len -= write_size; 138 len -= write_size;
313 current_data += write_size; 139 current_data += write_size;
314 bytes_so_far_ += write_size; 140 bytes_so_far_ += write_size;
315 } 141 }
316 142
317 download_stats::RecordDownloadWriteSize(data_len); 143 download_stats::RecordDownloadWriteSize(data_len);
318 download_stats::RecordDownloadWriteLoopCount(write_count); 144 download_stats::RecordDownloadWriteLoopCount(write_count);
319 145
320 if (calculate_hash_) 146 if (calculate_hash_)
321 secure_hash_->Update(data, data_len); 147 secure_hash_->Update(data, data_len);
322 148
323 return net::OK; 149 return content::DOWNLOAD_INTERRUPT_REASON_NONE;
324 } 150 }
325 151
326 net::Error BaseFile::Rename(const FilePath& new_path) { 152 content::DownloadInterruptReason BaseFile::Rename(const FilePath& new_path) {
327 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 153 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
328 154
329 // Save the information whether the download is in progress because 155 // Save the information whether the download is in progress because
330 // it will be overwritten by closing the file. 156 // it will be overwritten by closing the file.
331 bool saved_in_progress = in_progress(); 157 bool was_in_progress = in_progress();
332 158
333 bound_net_log_.AddEvent( 159 bound_net_log_.BeginEvent(
334 net::NetLog::TYPE_DOWNLOAD_FILE_RENAMED, 160 net::NetLog::TYPE_DOWNLOAD_FILE_RENAMED,
335 base::Bind(&download_net_logs::FileRenamedCallback, 161 base::Bind(&download_net_logs::FileRenamedCallback,
336 &full_path_, &new_path)); 162 &full_path_, &new_path));
337 163
164 content::DownloadInterruptReason rename_result =
165 content::DOWNLOAD_INTERRUPT_REASON_NONE;
166
338 // If the new path is same as the old one, there is no need to perform the 167 // If the new path is same as the old one, there is no need to perform the
339 // following renaming logic. 168 // following renaming logic.
340 if (new_path == full_path_) { 169 if (new_path != full_path_) {
Randy Smith (Not in Mondays) 2012/10/23 20:18:13 Why reverse the logic? I'm used to "if (X) { Y; r
asanka 2012/10/23 21:53:34 This is to avoid having multiple return points sin
Randy Smith (Not in Mondays) 2012/10/24 18:10:29 Ah, that makes sense.
341 // Don't close the file if we're not done (finished or canceled). 170 Close();
342 if (!saved_in_progress) 171 file_util::CreateDirectory(new_path.DirName());
343 Close();
344 172
345 return net::OK; 173 // A simple rename wouldn't work here since we want the file to have
174 // permissions / security descriptors that makes sense in the new directory.
175 rename_result = MoveFileAndAdjustPermissions(new_path);
176
177 if (rename_result == content::DOWNLOAD_INTERRUPT_REASON_NONE) {
178 full_path_ = new_path;
179 // Re-open the file if we were still using it.
180 if (was_in_progress)
181 rename_result = Open();
182 }
346 } 183 }
347 184
348 Close(); 185 bound_net_log_.EndEvent(net::NetLog::TYPE_DOWNLOAD_FILE_RENAMED);
Randy Smith (Not in Mondays) 2012/10/23 20:18:13 Why remove the "if (!saved_in_progres) Close()" pa
asanka 2012/10/23 21:53:34 If saved_in_progress is false, then the file_strea
349 186 return rename_result;
350 file_util::CreateDirectory(new_path.DirName());
351
352 #if defined(OS_WIN)
353 // We cannot rename because rename will keep the same security descriptor
354 // on the destination file. We want to recreate the security descriptor
355 // with the security that makes sense in the new path.
356 // |RenameFileAndResetSecurityDescriptor| returns a windows-specific
357 // error, whch we must translate into a net::Error.
358 net::Error rename_err =
359 RenameFileAndResetSecurityDescriptor(full_path_, new_path);
360 if (rename_err != net::OK)
361 return LOG_ERROR("RenameFileAndResetSecurityDescriptor", rename_err);
362 #elif defined(OS_POSIX)
363 {
364 // Similarly, on Unix, we're moving a temp file created with permissions
365 // 600 to |new_path|. Here, we try to fix up the destination file with
366 // appropriate permissions.
367 struct stat st;
368 // First check the file existence and create an empty file if it doesn't
369 // exist.
370 if (!file_util::PathExists(new_path)) {
371 int write_error = file_util::WriteFile(new_path, "", 0);
372 if (write_error < 0)
373 return LOG_ERROR("WriteFile", net::MapSystemError(errno));
374 }
375 int stat_error = stat(new_path.value().c_str(), &st);
376 bool stat_succeeded = (stat_error == 0);
377 if (!stat_succeeded)
378 LOG_ERROR("stat", net::MapSystemError(errno));
379
380 // TODO(estade): Move() falls back to copying and deleting when a simple
381 // rename fails. Copying sucks for large downloads. crbug.com/8737
382 if (!file_util::Move(full_path_, new_path))
383 return LOG_ERROR("Move", net::MapSystemError(errno));
384
385 if (stat_succeeded) {
386 // On Windows file systems (FAT, NTFS), chmod fails. This is OK.
387 int chmod_error = chmod(new_path.value().c_str(), st.st_mode);
388 if (chmod_error < 0)
389 LOG_ERROR("chmod", net::MapSystemError(errno));
390 }
391 }
392 #endif
393
394 full_path_ = new_path;
395
396 // We don't need to re-open the file if we're done (finished or canceled).
397 if (!saved_in_progress)
398 return net::OK;
399
400 return Open();
401 } 187 }
402 188
403 void BaseFile::Detach() { 189 void BaseFile::Detach() {
404 detached_ = true; 190 detached_ = true;
405 bound_net_log_.AddEvent(net::NetLog::TYPE_DOWNLOAD_FILE_DETACHED); 191 bound_net_log_.AddEvent(net::NetLog::TYPE_DOWNLOAD_FILE_DETACHED);
406 } 192 }
407 193
408 void BaseFile::Cancel() { 194 void BaseFile::Cancel() {
409 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 195 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
410 DCHECK(!detached_); 196 DCHECK(!detached_);
(...skipping 11 matching lines...) Expand all
422 208
423 void BaseFile::Finish() { 209 void BaseFile::Finish() {
424 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 210 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
425 211
426 if (calculate_hash_) 212 if (calculate_hash_)
427 secure_hash_->Finish(sha256_hash_, kSha256HashLen); 213 secure_hash_->Finish(sha256_hash_, kSha256HashLen);
428 214
429 Close(); 215 Close();
430 } 216 }
431 217
218 // OS_WIN, OS_MACOSX and OS_LINUX have specialized implementations.
219 #if !defined(OS_WIN) && !defined(OS_MACOSX) && !defined(OS_LINUX)
220 content::DownloadInterruptReason BaseFile::AnnotateWithSourceInformation() {
221 return content::DOWNLOAD_INTERRUPT_REASON_NONE;
222 }
223 #endif
224
225 int64 BaseFile::CurrentSpeed() const {
226 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
227 return CurrentSpeedAtTime(base::TimeTicks::Now());
228 }
229
432 bool BaseFile::GetHash(std::string* hash) { 230 bool BaseFile::GetHash(std::string* hash) {
433 DCHECK(!detached_); 231 DCHECK(!detached_);
434 hash->assign(reinterpret_cast<const char*>(sha256_hash_), 232 hash->assign(reinterpret_cast<const char*>(sha256_hash_),
435 sizeof(sha256_hash_)); 233 sizeof(sha256_hash_));
436 return (calculate_hash_ && !in_progress()); 234 return (calculate_hash_ && !in_progress());
437 } 235 }
438 236
439 std::string BaseFile::GetHashState() { 237 std::string BaseFile::GetHashState() {
440 if (!calculate_hash_) 238 if (!calculate_hash_)
441 return ""; 239 return "";
442 240
443 Pickle hash_state; 241 Pickle hash_state;
444 if (!secure_hash_->Serialize(&hash_state)) 242 if (!secure_hash_->Serialize(&hash_state))
445 return ""; 243 return "";
446 244
447 return std::string(reinterpret_cast<const char*>(hash_state.data()), 245 return std::string(reinterpret_cast<const char*>(hash_state.data()),
448 hash_state.size()); 246 hash_state.size());
449 } 247 }
450 248
451 bool BaseFile::SetHashState(const std::string& hash_state_bytes) {
452 if (!calculate_hash_)
453 return false;
454
455 Pickle hash_state(hash_state_bytes.c_str(), hash_state_bytes.size());
456 PickleIterator data_iterator(hash_state);
457
458 return secure_hash_->Deserialize(&data_iterator);
459 }
460
461 bool BaseFile::IsEmptyHash(const std::string& hash) { 249 bool BaseFile::IsEmptyHash(const std::string& hash) {
462 return (hash.size() == kSha256HashLen && 250 return (hash.size() == kSha256HashLen &&
463 0 == memcmp(hash.data(), kEmptySha256Hash, sizeof(kSha256HashLen))); 251 0 == memcmp(hash.data(), kEmptySha256Hash, sizeof(kSha256HashLen)));
464 } 252 }
465 253
466 void BaseFile::AnnotateWithSourceInformation() { 254 std::string BaseFile::DebugString() const {
467 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 255 return base::StringPrintf("{ source_url_ = \"%s\""
468 DCHECK(!detached_); 256 " full_path_ = \"%" PRFilePath "\""
469 257 " bytes_so_far_ = %" PRId64
470 #if defined(OS_WIN) 258 " detached_ = %c }",
471 // Sets the Zone to tell Windows that this file comes from the internet. 259 source_url_.spec().c_str(),
472 // We ignore the return value because a failure is not fatal. 260 full_path_.value().c_str(),
473 win_util::SetInternetZoneIdentifier(full_path_, 261 bytes_so_far_,
474 UTF8ToWide(source_url_.spec())); 262 detached_ ? 'T' : 'F');
475 #elif defined(OS_MACOSX)
476 content::AddQuarantineMetadataToFile(full_path_, source_url_, referrer_url_);
477 content::AddOriginMetadataToFile(full_path_, source_url_, referrer_url_);
478 #elif defined(OS_LINUX)
479 content::AddOriginMetadataToFile(full_path_, source_url_, referrer_url_);
480 #endif
481 } 263 }
482 264
483 void BaseFile::CreateFileStream() { 265 void BaseFile::CreateFileStream() {
484 file_stream_.reset(new net::FileStream(bound_net_log_.net_log())); 266 file_stream_.reset(new net::FileStream(bound_net_log_.net_log()));
485 file_stream_->SetBoundNetLogSource(bound_net_log_); 267 file_stream_->SetBoundNetLogSource(bound_net_log_);
486 } 268 }
487 269
488 net::Error BaseFile::Open() { 270 content::DownloadInterruptReason BaseFile::Open() {
489 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 271 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
490 DCHECK(!detached_); 272 DCHECK(!detached_);
491 DCHECK(!full_path_.empty()); 273 DCHECK(!full_path_.empty());
492 274
493 bound_net_log_.BeginEvent( 275 bound_net_log_.BeginEvent(
494 net::NetLog::TYPE_DOWNLOAD_FILE_OPENED, 276 net::NetLog::TYPE_DOWNLOAD_FILE_OPENED,
495 base::Bind(&download_net_logs::FileOpenedCallback, 277 base::Bind(&download_net_logs::FileOpenedCallback,
496 &full_path_, bytes_so_far_)); 278 &full_path_, bytes_so_far_));
497 279
498 // Create a new file stream if it is not provided. 280 // Create a new file stream if it is not provided.
499 if (!file_stream_.get()) { 281 if (!file_stream_.get()) {
500 CreateFileStream(); 282 CreateFileStream();
501 file_stream_->EnableErrorStatistics(); 283 file_stream_->EnableErrorStatistics();
502 int open_result = file_stream_->OpenSync( 284 int open_result = file_stream_->OpenSync(
503 full_path_, 285 full_path_,
504 base::PLATFORM_FILE_OPEN_ALWAYS | base::PLATFORM_FILE_WRITE); 286 base::PLATFORM_FILE_OPEN_ALWAYS | base::PLATFORM_FILE_WRITE);
505 if (open_result != net::OK) 287 if (open_result != net::OK) {
506 return ClearStream(LOG_ERROR("Open", open_result)); 288 ClearStream();
289 return LogNetError("Open", static_cast<net::Error>(open_result));
290 }
507 291
508 // We may be re-opening the file after rename. Always make sure we're 292 // We may be re-opening the file after rename. Always make sure we're
509 // writing at the end of the file. 293 // writing at the end of the file.
510 int64 seek_result = file_stream_->SeekSync(net::FROM_END, 0); 294 int64 seek_result = file_stream_->SeekSync(net::FROM_END, 0);
511 if (seek_result < 0) 295 if (seek_result < 0) {
512 return ClearStream(LOG_ERROR("Seek", seek_result)); 296 ClearStream();
297 return LogNetError("Seek", static_cast<net::Error>(seek_result));
298 }
513 } else { 299 } else {
514 file_stream_->SetBoundNetLogSource(bound_net_log_); 300 file_stream_->SetBoundNetLogSource(bound_net_log_);
515 } 301 }
516 302
517 return net::OK; 303 return content::DOWNLOAD_INTERRUPT_REASON_NONE;
518 } 304 }
519 305
520 void BaseFile::Close() { 306 void BaseFile::Close() {
521 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 307 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
522 308
523 bound_net_log_.AddEvent(net::NetLog::TYPE_DOWNLOAD_FILE_CLOSED); 309 bound_net_log_.AddEvent(net::NetLog::TYPE_DOWNLOAD_FILE_CLOSED);
524 310
525 if (file_stream_.get()) { 311 if (file_stream_.get()) {
526 #if defined(OS_CHROMEOS) 312 #if defined(OS_CHROMEOS)
527 // Currently we don't really care about the return value, since if it fails 313 // Currently we don't really care about the return value, since if it fails
528 // theres not much we can do. But we might in the future. 314 // theres not much we can do. But we might in the future.
529 file_stream_->FlushSync(); 315 file_stream_->FlushSync();
530 #endif 316 #endif
531 file_stream_->CloseSync(); 317 file_stream_->CloseSync();
532 ClearStream(net::OK); 318 ClearStream();
533 } 319 }
534 } 320 }
535 321
536 net::Error BaseFile::ClearStream(net::Error net_error) { 322 void BaseFile::ClearStream() {
537 // This should only be called when we have a stream. 323 // This should only be called when we have a stream.
538 DCHECK(file_stream_.get() != NULL); 324 DCHECK(file_stream_.get() != NULL);
539 file_stream_.reset(); 325 file_stream_.reset();
540 bound_net_log_.EndEvent(net::NetLog::TYPE_DOWNLOAD_FILE_OPENED); 326 bound_net_log_.EndEvent(net::NetLog::TYPE_DOWNLOAD_FILE_OPENED);
541 return net_error;
542 }
543
544 std::string BaseFile::DebugString() const {
545 return base::StringPrintf("{ source_url_ = \"%s\""
546 " full_path_ = \"%" PRFilePath "\""
547 " bytes_so_far_ = %" PRId64
548 " detached_ = %c }",
549 source_url_.spec().c_str(),
550 full_path_.value().c_str(),
551 bytes_so_far_,
552 detached_ ? 'T' : 'F');
553 } 327 }
554 328
555 int64 BaseFile::CurrentSpeedAtTime(base::TimeTicks current_time) const { 329 int64 BaseFile::CurrentSpeedAtTime(base::TimeTicks current_time) const {
556 base::TimeDelta diff = current_time - start_tick_; 330 base::TimeDelta diff = current_time - start_tick_;
557 int64 diff_ms = diff.InMilliseconds(); 331 int64 diff_ms = diff.InMilliseconds();
558 return diff_ms == 0 ? 0 : bytes_so_far() * 1000 / diff_ms; 332 return diff_ms == 0 ? 0 : bytes_so_far() * 1000 / diff_ms;
559 } 333 }
560 334
561 int64 BaseFile::CurrentSpeed() const { 335 bool BaseFile::SetHashState(const std::string& hash_state_bytes) {
Randy Smith (Not in Mondays) 2012/10/23 20:18:13 Suggestion (up to you): This is only called from
asanka 2012/10/23 21:53:34 Done.
562 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 336 if (!calculate_hash_)
563 return CurrentSpeedAtTime(base::TimeTicks::Now()); 337 return false;
338
339 Pickle hash_state(hash_state_bytes.c_str(), hash_state_bytes.size());
340 PickleIterator data_iterator(hash_state);
341
342 return secure_hash_->Deserialize(&data_iterator);
564 } 343 }
344
345 content::DownloadInterruptReason BaseFile::LogNetError(
346 const char* operation,
347 net::Error error) {
348 bound_net_log_.AddEvent(
349 net::NetLog::TYPE_DOWNLOAD_FILE_ERROR,
350 base::Bind(&download_net_logs::FileErrorCallback, operation, error));
351 return content::ConvertNetErrorToInterruptReason(
352 error, content::DOWNLOAD_INTERRUPT_FROM_DISK);
353 }
354
355 content::DownloadInterruptReason BaseFile::LogInterruptReason(
356 const char* operation,
357 int os_error,
358 content::DownloadInterruptReason reason) {
359 bound_net_log_.AddEvent(
360 net::NetLog::TYPE_DOWNLOAD_FILE_ERROR,
361 base::Bind(&download_net_logs::FileInterruptedCallback, operation,
362 os_error, reason));
363 return reason;
364 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698