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

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

Issue 319603003: [Downloads] Retry renames after transient failures. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Prepare to reland after XP test fix. Created 6 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 <windows.h> 7 #include <windows.h>
8 #include <cguid.h> 8 #include <cguid.h>
9 #include <objbase.h> 9 #include <objbase.h>
10 #include <shellapi.h> 10 #include <shellapi.h>
11 11
12 #include "base/files/file.h"
12 #include "base/files/file_util.h" 13 #include "base/files/file_util.h"
13 #include "base/guid.h" 14 #include "base/guid.h"
14 #include "base/metrics/histogram.h" 15 #include "base/metrics/histogram.h"
15 #include "base/strings/utf_string_conversions.h" 16 #include "base/strings/utf_string_conversions.h"
16 #include "base/threading/thread_restrictions.h" 17 #include "base/threading/thread_restrictions.h"
17 #include "content/browser/download/download_interrupt_reasons_impl.h" 18 #include "content/browser/download/download_interrupt_reasons_impl.h"
18 #include "content/browser/download/download_stats.h" 19 #include "content/browser/download/download_stats.h"
19 #include "content/browser/safe_util_win.h" 20 #include "content/browser/safe_util_win.h"
20 #include "content/public/browser/browser_thread.h" 21 #include "content/public/browser/browser_thread.h"
21 22
22 namespace content { 23 namespace content {
23 namespace { 24 namespace {
24 25
25 const int kAllSpecialShFileOperationCodes[] = { 26 const int kAllSpecialShFileOperationCodes[] = {
26 // Should be kept in sync with the case statement below. 27 // Should be kept in sync with the case statement below.
27 ERROR_ACCESS_DENIED, 28 ERROR_ACCESS_DENIED,
29 ERROR_SHARING_VIOLATION,
30 ERROR_INVALID_PARAMETER,
28 0x71, 31 0x71,
29 0x72, 32 0x72,
30 0x73, 33 0x73,
31 0x74, 34 0x74,
32 0x75, 35 0x75,
33 0x76, 36 0x76,
34 0x78, 37 0x78,
35 0x79, 38 0x79,
36 0x7A, 39 0x7A,
37 0x7C, 40 0x7C,
(...skipping 23 matching lines...) Expand all
61 // 64 //
62 // See http://msdn.microsoft.com/en-us/library/bb762164(VS.85).aspx. 65 // See http://msdn.microsoft.com/en-us/library/bb762164(VS.85).aspx.
63 DownloadInterruptReason MapShFileOperationCodes(int code) { 66 DownloadInterruptReason MapShFileOperationCodes(int code) {
64 DownloadInterruptReason result = DOWNLOAD_INTERRUPT_REASON_NONE; 67 DownloadInterruptReason result = DOWNLOAD_INTERRUPT_REASON_NONE;
65 68
66 // Check these pre-Win32 error codes first, then check for matches 69 // Check these pre-Win32 error codes first, then check for matches
67 // in Winerror.h. 70 // in Winerror.h.
68 // This switch statement should be kept in sync with the list of codes 71 // This switch statement should be kept in sync with the list of codes
69 // above. 72 // above.
70 switch (code) { 73 switch (code) {
71 // Not a pre-Win32 error code; here so that this particular 74 // Not a pre-Win32 error code; here so that this particular case shows up in
72 // case shows up in our histograms. This is redundant with the 75 // our histograms. Unfortunately, it is used not just to signal actual
73 // mapping function net::MapSystemError used later. 76 // ACCESS_DENIED errors, but many other errors as well. So we treat it as a
77 // transient error.
74 case ERROR_ACCESS_DENIED: // Access is denied. 78 case ERROR_ACCESS_DENIED: // Access is denied.
75 result = DOWNLOAD_INTERRUPT_REASON_FILE_ACCESS_DENIED; 79 result = DOWNLOAD_INTERRUPT_REASON_FILE_TRANSIENT_ERROR;
80 break;
81
82 // This isn't documented but returned from SHFileOperation. Sharing
83 // violations indicate that another process had the file open while we were
84 // trying to rename. Anti-virus is believed to be the cause of this error in
85 // the wild. Treated as a transient error on the assumption that the file
86 // will be made available for renaming at a later time.
87 case ERROR_SHARING_VIOLATION:
88 result = DOWNLOAD_INTERRUPT_REASON_FILE_TRANSIENT_ERROR;
89 break;
90
91 // This is also not a documented return value of SHFileOperation, but has
92 // been observed in the wild. We are treating it as a transient error based
93 // on the cases we have seen so far. See http://crbug.com/368455.
94 case ERROR_INVALID_PARAMETER:
95 result = DOWNLOAD_INTERRUPT_REASON_FILE_TRANSIENT_ERROR;
76 break; 96 break;
77 97
78 // The source and destination files are the same file. 98 // The source and destination files are the same file.
79 // DE_SAMEFILE == 0x71 99 // DE_SAMEFILE == 0x71
80 case 0x71: 100 case 0x71:
81 result = DOWNLOAD_INTERRUPT_REASON_FILE_FAILED; 101 result = DOWNLOAD_INTERRUPT_REASON_FILE_FAILED;
82 break; 102 break;
83 103
84 // The operation was canceled by the user, or silently canceled if the 104 // The operation was canceled by the user, or silently canceled if the
85 // appropriate flags were supplied to SHFileOperation. 105 // appropriate flags were supplied to SHFileOperation.
(...skipping 157 matching lines...) Expand 10 before | Expand all | Expand 10 after
243 } 263 }
244 264
245 if (result == DOWNLOAD_INTERRUPT_REASON_FILE_ACCESS_DENIED) { 265 if (result == DOWNLOAD_INTERRUPT_REASON_FILE_ACCESS_DENIED) {
246 UMA_HISTOGRAM_CUSTOM_ENUMERATION( 266 UMA_HISTOGRAM_CUSTOM_ENUMERATION(
247 "Download.MapWinShErrorAccessDenied", code, 267 "Download.MapWinShErrorAccessDenied", code,
248 base::CustomHistogram::ArrayToCustomRanges( 268 base::CustomHistogram::ArrayToCustomRanges(
249 kAllSpecialShFileOperationCodes, 269 kAllSpecialShFileOperationCodes,
250 arraysize(kAllSpecialShFileOperationCodes))); 270 arraysize(kAllSpecialShFileOperationCodes)));
251 } 271 }
252 272
273 if (result == DOWNLOAD_INTERRUPT_REASON_FILE_TRANSIENT_ERROR) {
274 UMA_HISTOGRAM_CUSTOM_ENUMERATION(
275 "Download.MapWinShErrorTransientError", code,
276 base::CustomHistogram::ArrayToCustomRanges(
277 kAllSpecialShFileOperationCodes,
278 arraysize(kAllSpecialShFileOperationCodes)));
279 }
280
253 if (result != DOWNLOAD_INTERRUPT_REASON_NONE) 281 if (result != DOWNLOAD_INTERRUPT_REASON_NONE)
254 return result; 282 return result;
255 283
256 // If not one of the above codes, it should be a standard Windows error code. 284 // If not one of the above codes, it should be a standard Windows error code.
257 return ConvertNetErrorToInterruptReason( 285 return ConvertFileErrorToInterruptReason(
258 net::MapSystemError(code), DOWNLOAD_INTERRUPT_FROM_DISK); 286 base::File::OSErrorToFileError(code));
259 } 287 }
260 288
261 // Maps a return code from ScanAndSaveDownloadedFile() to a 289 // Maps a return code from ScanAndSaveDownloadedFile() to a
262 // DownloadInterruptReason. The return code in |result| is usually from the 290 // DownloadInterruptReason. The return code in |result| is usually from the
263 // final IAttachmentExecute::Save() call. 291 // final IAttachmentExecute::Save() call.
264 DownloadInterruptReason MapScanAndSaveErrorCodeToInterruptReason( 292 DownloadInterruptReason MapScanAndSaveErrorCodeToInterruptReason(
265 HRESULT result) { 293 HRESULT result) {
266 if (SUCCEEDED(result)) 294 if (SUCCEEDED(result))
267 return DOWNLOAD_INTERRUPT_REASON_NONE; 295 return DOWNLOAD_INTERRUPT_REASON_NONE;
268 296
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
303 source.append(1, L'\0'); 331 source.append(1, L'\0');
304 target.append(1, L'\0'); 332 target.append(1, L'\0');
305 333
306 SHFILEOPSTRUCT move_info = {0}; 334 SHFILEOPSTRUCT move_info = {0};
307 move_info.wFunc = FO_MOVE; 335 move_info.wFunc = FO_MOVE;
308 move_info.pFrom = source.c_str(); 336 move_info.pFrom = source.c_str();
309 move_info.pTo = target.c_str(); 337 move_info.pTo = target.c_str();
310 move_info.fFlags = FOF_SILENT | FOF_NOCONFIRMATION | FOF_NOERRORUI | 338 move_info.fFlags = FOF_SILENT | FOF_NOCONFIRMATION | FOF_NOERRORUI |
311 FOF_NOCONFIRMMKDIR | FOF_NOCOPYSECURITYATTRIBS; 339 FOF_NOCONFIRMMKDIR | FOF_NOCOPYSECURITYATTRIBS;
312 340
341 base::TimeTicks now = base::TimeTicks::Now();
313 int result = SHFileOperation(&move_info); 342 int result = SHFileOperation(&move_info);
314 DownloadInterruptReason interrupt_reason = DOWNLOAD_INTERRUPT_REASON_NONE; 343 DownloadInterruptReason interrupt_reason = DOWNLOAD_INTERRUPT_REASON_NONE;
315 344
316 if (result == 0 && move_info.fAnyOperationsAborted) 345 if (result == 0 && move_info.fAnyOperationsAborted)
317 interrupt_reason = DOWNLOAD_INTERRUPT_REASON_FILE_FAILED; 346 interrupt_reason = DOWNLOAD_INTERRUPT_REASON_FILE_FAILED;
318 else if (result != 0) 347 else if (result != 0)
319 interrupt_reason = MapShFileOperationCodes(result); 348 interrupt_reason = MapShFileOperationCodes(result);
320 349
321 if (interrupt_reason != DOWNLOAD_INTERRUPT_REASON_NONE) 350 if (interrupt_reason != DOWNLOAD_INTERRUPT_REASON_NONE)
322 return LogInterruptReason("SHFileOperation", result, interrupt_reason); 351 return LogInterruptReason("SHFileOperation", result, interrupt_reason);
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
358 RecordDownloadCount(FILE_MISSING_AFTER_SUCCESSFUL_SCAN_COUNT); 387 RecordDownloadCount(FILE_MISSING_AFTER_SUCCESSFUL_SCAN_COUNT);
359 result = DOWNLOAD_INTERRUPT_REASON_FILE_SECURITY_CHECK_FAILED; 388 result = DOWNLOAD_INTERRUPT_REASON_FILE_SECURITY_CHECK_FAILED;
360 } 389 }
361 LogInterruptReason("ScanAndSaveDownloadedFile", hr, result); 390 LogInterruptReason("ScanAndSaveDownloadedFile", hr, result);
362 } 391 }
363 bound_net_log_.EndEvent(net::NetLog::TYPE_DOWNLOAD_FILE_ANNOTATED); 392 bound_net_log_.EndEvent(net::NetLog::TYPE_DOWNLOAD_FILE_ANNOTATED);
364 return result; 393 return result;
365 } 394 }
366 395
367 } // namespace content 396 } // namespace content
OLDNEW
« no previous file with comments | « content/browser/download/base_file_unittest.cc ('k') | content/browser/download/download_file_impl.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698