Index: content/browser/download/base_file.cc |
diff --git a/content/browser/download/base_file.cc b/content/browser/download/base_file.cc |
index 59dfa839cd51dca2373f2b6204d5a64c418fb41c..b95ef97ed98c372ddddcb82f12144b11418735ee 100644 |
--- a/content/browser/download/base_file.cc |
+++ b/content/browser/download/base_file.cc |
@@ -44,7 +44,8 @@ DownloadInterruptReason BaseFile::Initialize( |
base::File file, |
int64_t bytes_so_far, |
const std::string& hash_so_far, |
- std::unique_ptr<crypto::SecureHash> hash_state) { |
+ std::unique_ptr<crypto::SecureHash> hash_state, |
+ bool is_sparse_file) { |
DCHECK_CURRENTLY_ON(BrowserThread::FILE); |
DCHECK(!detached_); |
@@ -70,6 +71,8 @@ DownloadInterruptReason BaseFile::Initialize( |
bytes_so_far_ = bytes_so_far; |
secure_hash_ = std::move(hash_state); |
+ is_sparse_file_ = is_sparse_file; |
+ DCHECK(!is_sparse_file_ || !secure_hash_); |
file_ = std::move(file); |
return Open(hash_so_far); |
@@ -77,9 +80,13 @@ DownloadInterruptReason BaseFile::Initialize( |
DownloadInterruptReason BaseFile::AppendDataToFile(const char* data, |
size_t data_len) { |
- DCHECK_CURRENTLY_ON(BrowserThread::FILE); |
- DCHECK(!detached_); |
+ DCHECK(!is_sparse_file_); |
+ return WriteDataToFile(bytes_so_far_, data, data_len); |
+} |
+DownloadInterruptReason BaseFile::WriteDataToFile(int64_t offset, |
+ const char* data, |
+ size_t data_len) { |
// NOTE(benwells): The above DCHECK won't be present in release builds, |
// so we log any occurences to see how common this error is in the wild. |
if (detached_) |
@@ -93,27 +100,16 @@ DownloadInterruptReason BaseFile::AppendDataToFile(const char* data, |
if (data_len == 0) |
return DOWNLOAD_INTERRUPT_REASON_NONE; |
- // The Write call below is not guaranteed to write all the data. |
- size_t write_count = 0; |
- size_t len = data_len; |
- const char* current_data = data; |
net_log_.BeginEvent(net::NetLogEventType::DOWNLOAD_FILE_WRITTEN); |
- while (len > 0) { |
- write_count++; |
- int write_result = file_.WriteAtCurrentPos(current_data, len); |
- DCHECK_NE(0, write_result); |
- |
- // Report errors on file writes. |
- if (write_result < 0) |
- return LogSystemError("Write", logging::GetLastSystemErrorCode()); |
- |
- // Update status. |
- size_t write_size = static_cast<size_t>(write_result); |
- DCHECK_LE(write_size, len); |
- len -= write_size; |
- current_data += write_size; |
- bytes_so_far_ += write_size; |
- } |
+ int write_result = file_.Write(offset, data, data_len); |
+ DCHECK_NE(0, write_result); |
+ |
+ // Report errors on file writes. |
+ if (write_result < 0) |
+ return LogSystemError("Write", logging::GetLastSystemErrorCode()); |
+ |
+ DCHECK_EQ(static_cast<size_t>(write_result), data_len); |
+ bytes_so_far_ += data_len; |
net_log_.EndEvent(net::NetLogEventType::DOWNLOAD_FILE_WRITTEN, |
net::NetLog::Int64Callback("bytes", data_len)); |
@@ -186,6 +182,10 @@ void BaseFile::Cancel() { |
std::unique_ptr<crypto::SecureHash> BaseFile::Finish() { |
DCHECK_CURRENTLY_ON(BrowserThread::FILE); |
+ |
+ // TODO(qinmin): verify that all the holes have been filled. |
+ if (is_sparse_file_) |
+ CalculatePartialHash(std::string()); |
Close(); |
return std::move(secure_hash_); |
} |
@@ -288,6 +288,16 @@ DownloadInterruptReason BaseFile::Open(const std::string& hash_so_far) { |
net::NetLogEventType::DOWNLOAD_FILE_OPENED, |
base::Bind(&FileOpenedNetLogCallback, &full_path_, bytes_so_far_)); |
+ // For sparse file, skip hash validation. |
+ if (is_sparse_file_) { |
+ if (file_.GetLength() < bytes_so_far_) { |
+ ClearFile(); |
+ return LogInterruptReason("File has fewer written bytes than expected", 0, |
+ DOWNLOAD_INTERRUPT_REASON_FILE_TOO_SHORT); |
+ } |
+ return DOWNLOAD_INTERRUPT_REASON_NONE; |
+ } |
+ |
if (!secure_hash_) { |
DownloadInterruptReason reason = CalculatePartialHash(hash_so_far); |
if (reason != DOWNLOAD_INTERRUPT_REASON_NONE) { |