| 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
|
| index b2706e79bad88ea7df49d84aceb7e4e629e58467..fec1454d57b4b517193bb11a0f8df0d1ba1e77b0 100644
|
| --- a/content/browser/download/base_file_win.cc
|
| +++ b/content/browser/download/base_file_win.cc
|
| @@ -9,6 +9,7 @@
|
| #include <objbase.h>
|
| #include <shellapi.h>
|
|
|
| +#include "base/files/file.h"
|
| #include "base/files/file_util.h"
|
| #include "base/guid.h"
|
| #include "base/metrics/histogram.h"
|
| @@ -25,6 +26,8 @@ namespace {
|
| const int kAllSpecialShFileOperationCodes[] = {
|
| // Should be kept in sync with the case statement below.
|
| ERROR_ACCESS_DENIED,
|
| + ERROR_SHARING_VIOLATION,
|
| + ERROR_INVALID_PARAMETER,
|
| 0x71,
|
| 0x72,
|
| 0x73,
|
| @@ -68,11 +71,28 @@ DownloadInterruptReason MapShFileOperationCodes(int code) {
|
| // This switch statement should be kept in sync with the list of codes
|
| // above.
|
| switch (code) {
|
| - // Not a pre-Win32 error code; here so that this particular
|
| - // case shows up in our histograms. This is redundant with the
|
| - // mapping function net::MapSystemError used later.
|
| + // Not a pre-Win32 error code; here so that this particular case shows up in
|
| + // our histograms. Unfortunately, it is used not just to signal actual
|
| + // ACCESS_DENIED errors, but many other errors as well. So we treat it as a
|
| + // transient error.
|
| case ERROR_ACCESS_DENIED: // Access is denied.
|
| - result = DOWNLOAD_INTERRUPT_REASON_FILE_ACCESS_DENIED;
|
| + result = DOWNLOAD_INTERRUPT_REASON_FILE_TRANSIENT_ERROR;
|
| + break;
|
| +
|
| + // This isn't documented but returned from SHFileOperation. Sharing
|
| + // violations indicate that another process had the file open while we were
|
| + // trying to rename. Anti-virus is believed to be the cause of this error in
|
| + // the wild. Treated as a transient error on the assumption that the file
|
| + // will be made available for renaming at a later time.
|
| + case ERROR_SHARING_VIOLATION:
|
| + result = DOWNLOAD_INTERRUPT_REASON_FILE_TRANSIENT_ERROR;
|
| + break;
|
| +
|
| + // This is also not a documented return value of SHFileOperation, but has
|
| + // been observed in the wild. We are treating it as a transient error based
|
| + // on the cases we have seen so far. See http://crbug.com/368455.
|
| + case ERROR_INVALID_PARAMETER:
|
| + result = DOWNLOAD_INTERRUPT_REASON_FILE_TRANSIENT_ERROR;
|
| break;
|
|
|
| // The source and destination files are the same file.
|
| @@ -250,12 +270,20 @@ DownloadInterruptReason MapShFileOperationCodes(int code) {
|
| arraysize(kAllSpecialShFileOperationCodes)));
|
| }
|
|
|
| + if (result == DOWNLOAD_INTERRUPT_REASON_FILE_TRANSIENT_ERROR) {
|
| + UMA_HISTOGRAM_CUSTOM_ENUMERATION(
|
| + "Download.MapWinShErrorTransientError", code,
|
| + base::CustomHistogram::ArrayToCustomRanges(
|
| + kAllSpecialShFileOperationCodes,
|
| + arraysize(kAllSpecialShFileOperationCodes)));
|
| + }
|
| +
|
| if (result != DOWNLOAD_INTERRUPT_REASON_NONE)
|
| return result;
|
|
|
| // If not one of the above codes, it should be a standard Windows error code.
|
| - return ConvertNetErrorToInterruptReason(
|
| - net::MapSystemError(code), DOWNLOAD_INTERRUPT_FROM_DISK);
|
| + return ConvertFileErrorToInterruptReason(
|
| + base::File::OSErrorToFileError(code));
|
| }
|
|
|
| // Maps a return code from ScanAndSaveDownloadedFile() to a
|
| @@ -310,6 +338,7 @@ DownloadInterruptReason BaseFile::MoveFileAndAdjustPermissions(
|
| move_info.fFlags = FOF_SILENT | FOF_NOCONFIRMATION | FOF_NOERRORUI |
|
| FOF_NOCONFIRMMKDIR | FOF_NOCOPYSECURITYATTRIBS;
|
|
|
| + base::TimeTicks now = base::TimeTicks::Now();
|
| int result = SHFileOperation(&move_info);
|
| DownloadInterruptReason interrupt_reason = DOWNLOAD_INTERRUPT_REASON_NONE;
|
|
|
|
|