OLD | NEW |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 |
OLD | NEW |