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

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

Issue 2695153002: Refactor BaseFile class to support sparse files (Closed)
Patch Set: remove the while loop around write Created 3 years, 10 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
« no previous file with comments | « content/browser/download/base_file.h ('k') | content/browser/download/base_file_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 <utility> 7 #include <utility>
8 8
9 #include "base/bind.h" 9 #include "base/bind.h"
10 #include "base/files/file.h" 10 #include "base/files/file.h"
(...skipping 26 matching lines...) Expand all
37 else 37 else
38 Cancel(); // Will delete the file. 38 Cancel(); // Will delete the file.
39 } 39 }
40 40
41 DownloadInterruptReason BaseFile::Initialize( 41 DownloadInterruptReason BaseFile::Initialize(
42 const base::FilePath& full_path, 42 const base::FilePath& full_path,
43 const base::FilePath& default_directory, 43 const base::FilePath& default_directory,
44 base::File file, 44 base::File file,
45 int64_t bytes_so_far, 45 int64_t bytes_so_far,
46 const std::string& hash_so_far, 46 const std::string& hash_so_far,
47 std::unique_ptr<crypto::SecureHash> hash_state) { 47 std::unique_ptr<crypto::SecureHash> hash_state,
48 bool is_sparse_file) {
48 DCHECK_CURRENTLY_ON(BrowserThread::FILE); 49 DCHECK_CURRENTLY_ON(BrowserThread::FILE);
49 DCHECK(!detached_); 50 DCHECK(!detached_);
50 51
51 if (full_path.empty()) { 52 if (full_path.empty()) {
52 base::FilePath initial_directory(default_directory); 53 base::FilePath initial_directory(default_directory);
53 base::FilePath temp_file; 54 base::FilePath temp_file;
54 if (initial_directory.empty()) { 55 if (initial_directory.empty()) {
55 initial_directory = 56 initial_directory =
56 GetContentClient()->browser()->GetDefaultDownloadDirectory(); 57 GetContentClient()->browser()->GetDefaultDownloadDirectory();
57 } 58 }
58 // |initial_directory| can still be empty if ContentBrowserClient returned 59 // |initial_directory| can still be empty if ContentBrowserClient returned
59 // an empty path for the downloads directory. 60 // an empty path for the downloads directory.
60 if ((initial_directory.empty() || 61 if ((initial_directory.empty() ||
61 !base::CreateTemporaryFileInDir(initial_directory, &temp_file)) && 62 !base::CreateTemporaryFileInDir(initial_directory, &temp_file)) &&
62 !base::CreateTemporaryFile(&temp_file)) { 63 !base::CreateTemporaryFile(&temp_file)) {
63 return LogInterruptReason("Unable to create", 0, 64 return LogInterruptReason("Unable to create", 0,
64 DOWNLOAD_INTERRUPT_REASON_FILE_FAILED); 65 DOWNLOAD_INTERRUPT_REASON_FILE_FAILED);
65 } 66 }
66 full_path_ = temp_file; 67 full_path_ = temp_file;
67 } else { 68 } else {
68 full_path_ = full_path; 69 full_path_ = full_path;
69 } 70 }
70 71
71 bytes_so_far_ = bytes_so_far; 72 bytes_so_far_ = bytes_so_far;
72 secure_hash_ = std::move(hash_state); 73 secure_hash_ = std::move(hash_state);
74 is_sparse_file_ = is_sparse_file;
75 DCHECK(!is_sparse_file_ || !secure_hash_);
73 file_ = std::move(file); 76 file_ = std::move(file);
74 77
75 return Open(hash_so_far); 78 return Open(hash_so_far);
76 } 79 }
77 80
78 DownloadInterruptReason BaseFile::AppendDataToFile(const char* data, 81 DownloadInterruptReason BaseFile::AppendDataToFile(const char* data,
79 size_t data_len) { 82 size_t data_len) {
80 DCHECK_CURRENTLY_ON(BrowserThread::FILE); 83 DCHECK(!is_sparse_file_);
81 DCHECK(!detached_); 84 return WriteDataToFile(bytes_so_far_, data, data_len);
85 }
82 86
87 DownloadInterruptReason BaseFile::WriteDataToFile(int64_t offset,
88 const char* data,
89 size_t data_len) {
83 // NOTE(benwells): The above DCHECK won't be present in release builds, 90 // NOTE(benwells): The above DCHECK won't be present in release builds,
84 // so we log any occurences to see how common this error is in the wild. 91 // so we log any occurences to see how common this error is in the wild.
85 if (detached_) 92 if (detached_)
86 RecordDownloadCount(APPEND_TO_DETACHED_FILE_COUNT); 93 RecordDownloadCount(APPEND_TO_DETACHED_FILE_COUNT);
87 94
88 if (!file_.IsValid()) 95 if (!file_.IsValid())
89 return LogInterruptReason("No file stream on append", 0, 96 return LogInterruptReason("No file stream on append", 0,
90 DOWNLOAD_INTERRUPT_REASON_FILE_FAILED); 97 DOWNLOAD_INTERRUPT_REASON_FILE_FAILED);
91 98
92 // TODO(phajdan.jr): get rid of this check. 99 // TODO(phajdan.jr): get rid of this check.
93 if (data_len == 0) 100 if (data_len == 0)
94 return DOWNLOAD_INTERRUPT_REASON_NONE; 101 return DOWNLOAD_INTERRUPT_REASON_NONE;
95 102
96 // The Write call below is not guaranteed to write all the data.
97 size_t write_count = 0;
98 size_t len = data_len;
99 const char* current_data = data;
100 net_log_.BeginEvent(net::NetLogEventType::DOWNLOAD_FILE_WRITTEN); 103 net_log_.BeginEvent(net::NetLogEventType::DOWNLOAD_FILE_WRITTEN);
101 while (len > 0) { 104 int write_result = file_.Write(offset, data, data_len);
102 write_count++; 105 DCHECK_NE(0, write_result);
103 int write_result = file_.WriteAtCurrentPos(current_data, len);
104 DCHECK_NE(0, write_result);
105 106
106 // Report errors on file writes. 107 // Report errors on file writes.
107 if (write_result < 0) 108 if (write_result < 0)
108 return LogSystemError("Write", logging::GetLastSystemErrorCode()); 109 return LogSystemError("Write", logging::GetLastSystemErrorCode());
109 110
110 // Update status. 111 DCHECK_EQ(static_cast<size_t>(write_result), data_len);
111 size_t write_size = static_cast<size_t>(write_result); 112 bytes_so_far_ += data_len;
112 DCHECK_LE(write_size, len);
113 len -= write_size;
114 current_data += write_size;
115 bytes_so_far_ += write_size;
116 }
117 net_log_.EndEvent(net::NetLogEventType::DOWNLOAD_FILE_WRITTEN, 113 net_log_.EndEvent(net::NetLogEventType::DOWNLOAD_FILE_WRITTEN,
118 net::NetLog::Int64Callback("bytes", data_len)); 114 net::NetLog::Int64Callback("bytes", data_len));
119 115
120 if (secure_hash_) 116 if (secure_hash_)
121 secure_hash_->Update(data, data_len); 117 secure_hash_->Update(data, data_len);
122 118
123 return DOWNLOAD_INTERRUPT_REASON_NONE; 119 return DOWNLOAD_INTERRUPT_REASON_NONE;
124 } 120 }
125 121
126 DownloadInterruptReason BaseFile::Rename(const base::FilePath& new_path) { 122 DownloadInterruptReason BaseFile::Rename(const base::FilePath& new_path) {
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after
179 if (!full_path_.empty()) { 175 if (!full_path_.empty()) {
180 net_log_.AddEvent(net::NetLogEventType::DOWNLOAD_FILE_DELETED); 176 net_log_.AddEvent(net::NetLogEventType::DOWNLOAD_FILE_DELETED);
181 base::DeleteFile(full_path_, false); 177 base::DeleteFile(full_path_, false);
182 } 178 }
183 179
184 Detach(); 180 Detach();
185 } 181 }
186 182
187 std::unique_ptr<crypto::SecureHash> BaseFile::Finish() { 183 std::unique_ptr<crypto::SecureHash> BaseFile::Finish() {
188 DCHECK_CURRENTLY_ON(BrowserThread::FILE); 184 DCHECK_CURRENTLY_ON(BrowserThread::FILE);
185
186 // TODO(qinmin): verify that all the holes have been filled.
187 if (is_sparse_file_)
188 CalculatePartialHash(std::string());
189 Close(); 189 Close();
190 return std::move(secure_hash_); 190 return std::move(secure_hash_);
191 } 191 }
192 192
193 std::string BaseFile::DebugString() const { 193 std::string BaseFile::DebugString() const {
194 return base::StringPrintf( 194 return base::StringPrintf(
195 "{ " 195 "{ "
196 " full_path_ = \"%" PRFilePath 196 " full_path_ = \"%" PRFilePath
197 "\"" 197 "\""
198 " bytes_so_far_ = %" PRId64 " detached_ = %c }", 198 " bytes_so_far_ = %" PRId64 " detached_ = %c }",
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after
281 if (!file_.IsValid()) { 281 if (!file_.IsValid()) {
282 return LogNetError("Open/Initialize File", 282 return LogNetError("Open/Initialize File",
283 net::FileErrorToNetError(file_.error_details())); 283 net::FileErrorToNetError(file_.error_details()));
284 } 284 }
285 } 285 }
286 286
287 net_log_.BeginEvent( 287 net_log_.BeginEvent(
288 net::NetLogEventType::DOWNLOAD_FILE_OPENED, 288 net::NetLogEventType::DOWNLOAD_FILE_OPENED,
289 base::Bind(&FileOpenedNetLogCallback, &full_path_, bytes_so_far_)); 289 base::Bind(&FileOpenedNetLogCallback, &full_path_, bytes_so_far_));
290 290
291 // For sparse file, skip hash validation.
292 if (is_sparse_file_) {
293 if (file_.GetLength() < bytes_so_far_) {
294 ClearFile();
295 return LogInterruptReason("File has fewer written bytes than expected", 0,
296 DOWNLOAD_INTERRUPT_REASON_FILE_TOO_SHORT);
297 }
298 return DOWNLOAD_INTERRUPT_REASON_NONE;
299 }
300
291 if (!secure_hash_) { 301 if (!secure_hash_) {
292 DownloadInterruptReason reason = CalculatePartialHash(hash_so_far); 302 DownloadInterruptReason reason = CalculatePartialHash(hash_so_far);
293 if (reason != DOWNLOAD_INTERRUPT_REASON_NONE) { 303 if (reason != DOWNLOAD_INTERRUPT_REASON_NONE) {
294 ClearFile(); 304 ClearFile();
295 return reason; 305 return reason;
296 } 306 }
297 } 307 }
298 308
299 int64_t file_size = file_.Seek(base::File::FROM_END, 0); 309 int64_t file_size = file_.Seek(base::File::FROM_END, 0);
300 if (file_size < 0) { 310 if (file_size < 0) {
(...skipping 155 matching lines...) Expand 10 before | Expand all | Expand 10 after
456 #else // !OS_WIN && !OS_MACOSX && !OS_LINUX 466 #else // !OS_WIN && !OS_MACOSX && !OS_LINUX
457 DownloadInterruptReason BaseFile::AnnotateWithSourceInformation( 467 DownloadInterruptReason BaseFile::AnnotateWithSourceInformation(
458 const std::string& client_guid, 468 const std::string& client_guid,
459 const GURL& source_url, 469 const GURL& source_url,
460 const GURL& referrer_url) { 470 const GURL& referrer_url) {
461 return DOWNLOAD_INTERRUPT_REASON_NONE; 471 return DOWNLOAD_INTERRUPT_REASON_NONE;
462 } 472 }
463 #endif 473 #endif
464 474
465 } // namespace content 475 } // namespace content
OLDNEW
« no previous file with comments | « content/browser/download/base_file.h ('k') | content/browser/download/base_file_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698