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 #ifndef CONTENT_BROWSER_DOWNLOAD_BASE_FILE_H_ | 5 #ifndef CONTENT_BROWSER_DOWNLOAD_BASE_FILE_H_ |
6 #define CONTENT_BROWSER_DOWNLOAD_BASE_FILE_H_ | 6 #define CONTENT_BROWSER_DOWNLOAD_BASE_FILE_H_ |
7 | 7 |
8 #include <stddef.h> | 8 #include <stddef.h> |
9 #include <stdint.h> | 9 #include <stdint.h> |
10 | 10 |
(...skipping 15 matching lines...) Expand all Loading... |
26 | 26 |
27 namespace content { | 27 namespace content { |
28 | 28 |
29 // File being downloaded and saved to disk. This is a base class | 29 // File being downloaded and saved to disk. This is a base class |
30 // for DownloadFile and SaveFile, which keep more state information. BaseFile | 30 // for DownloadFile and SaveFile, which keep more state information. BaseFile |
31 // considers itself the owner of the physical file and will delete it when the | 31 // considers itself the owner of the physical file and will delete it when the |
32 // BaseFile object is destroyed unless the ownership is revoked via a call to | 32 // BaseFile object is destroyed unless the ownership is revoked via a call to |
33 // Detach(). | 33 // Detach(). |
34 class CONTENT_EXPORT BaseFile { | 34 class CONTENT_EXPORT BaseFile { |
35 public: | 35 public: |
| 36 // Enum to indicate whether the file is exclusived owned, or shared among |
| 37 // multiple writers. |
| 38 enum AccessMode { |
| 39 EXCLUSIVE = 0, |
| 40 SHARED, |
| 41 }; |
| 42 |
36 // May be constructed on any thread. All other routines (including | 43 // May be constructed on any thread. All other routines (including |
37 // destruction) must occur on the FILE thread. | 44 // destruction) must occur on the FILE thread. |
38 BaseFile(const net::NetLogWithSource& net_log); | 45 BaseFile(const net::NetLogWithSource& net_log); |
39 ~BaseFile(); | 46 ~BaseFile(); |
40 | 47 |
41 // Returns DOWNLOAD_INTERRUPT_REASON_NONE on success, or a | 48 // Returns DOWNLOAD_INTERRUPT_REASON_NONE on success, or a |
42 // DownloadInterruptReason on failure. Upon success, the file at |full_path()| | 49 // DownloadInterruptReason on failure. Upon success, the file at |full_path()| |
43 // is assumed to be owned by the BaseFile. It will be deleted when the | 50 // is assumed to be owned by the BaseFile. It will be deleted when the |
44 // BaseFile object is destroyed unless Detach() is called before destroying | 51 // BaseFile object is destroyed unless Detach() is called before destroying |
45 // the BaseFile instance. | 52 // the BaseFile instance. |
46 // | 53 // |
47 // |full_path|: Full path to the download file. Can be empty, in which case | 54 // |full_path|: Full path to the download file. Can be empty, in which case |
48 // the rules described in |default_directory| will be used to generate a | 55 // the rules described in |default_directory| will be used to generate a |
49 // temporary filename. | 56 // temporary filename. |
50 // | 57 // |
51 // |default_directory|: specifies the directory to create the temporary file | 58 // |default_directory|: specifies the directory to create the temporary file |
52 // in if |full_path| is empty. If |default_directory| and |full_path| are | 59 // in if |full_path| is empty. If |default_directory| and |full_path| are |
53 // empty, then a temporary file will be created in the default download | 60 // empty, then a temporary file will be created in the default download |
54 // location as determined by ContentBrowserClient. | 61 // location as determined by ContentBrowserClient. |
55 // | 62 // |
56 // |file|: The base::File handle to use. If specified, BaseFile will not open | 63 // |file|: The base::File handle to use. If specified, BaseFile will not open |
57 // a file and will use this handle. The file should be opened for both | 64 // a file and will use this handle. The file should be opened for both |
58 // read and write. Only makes sense if |full_path| is non-empty since it | 65 // read and write. Only makes sense if |full_path| is non-empty since it |
59 // implies that the caller already knows the path to the file. There's no | 66 // implies that the caller already knows the path to the file. There's no |
60 // perfect way to come up with a canonical path for a file. So BaseFile | 67 // perfect way to come up with a canonical path for a file. So BaseFile |
61 // will not attempt to determine the |full_path|. | 68 // will not attempt to determine the |full_path|. |
62 // | 69 // |
63 // |bytes_so_far|: If a file is provided (via |full_path| or |file|), then | 70 // |offset|: If a file is provided (via |full_path| or |file|), then this |
64 // this argument specifies the size of the file to expect. It is legal for | 71 // argument specifies the starting position to write the file. If |
65 // the file to be larger, in which case the file will be truncated down to | 72 // |access_mode| is EXCLUSIVE, this value should be the size of the file |
66 // this size. However, if the file is shorter, then the operation will | 73 // to expect. It is legal for the file to be larger, in which case the |
67 // fail with DOWNLOAD_INTERRUPT_REASON_FILE_TOO_SHORT. | 74 // file will be truncated down to this size. However, if the file is |
| 75 // shorter, then the operation will fail with |
| 76 // DOWNLOAD_INTERRUPT_REASON_FILE_TOO_SHORT. If |access_mode_| is SHARED, |
| 77 // file size check is ignored as the writer is expecting other writers to |
| 78 // fill the gaps or append more data. |
68 // | 79 // |
69 // |hash_so_far|: If |bytes_so_far| is non-zero, this specifies the SHA-256 | 80 // |hash_so_far|: If |offset| is non-zero, this specifies the SHA-256 |
70 // hash of the first |bytes_so_far| bytes of the target file. If | 81 // hash of the first |offset| bytes of the target file. If |
71 // specified, BaseFile will read the first |bytes_so_far| of the target | 82 // specified, BaseFile will read the first |offset| of the target |
72 // file in order to calculate the hash and verify that the file matches. | 83 // file in order to calculate the hash and verify that the file matches. |
73 // If there's a mismatch, then the operation fails with | 84 // If there's a mismatch, then the operation fails with |
74 // DOWNLOAD_INTERRUPT_REASON_FILE_HASH_MISMATCH. Not used if |hash_state| | 85 // DOWNLOAD_INTERRUPT_REASON_FILE_HASH_MISMATCH. Not used if |hash_state| |
75 // is also specified. | 86 // is also specified or |access_mode| is equal to SHARED. |
76 // | 87 // |
77 // |hash_state|: The partial hash object to use. Only meaningful if there's a | 88 // |hash_state|: The partial hash object to use. Only meaningful if there's a |
78 // preexisting target file and it is non-empty (i.e. bytes_so_far is | 89 // preexisting target file and it is non-empty (i.e. offset is |
79 // non-zero). If specified, BaseFile will assume that the bytes up to | 90 // non-zero). If specified, BaseFile will assume that the bytes up to |
80 // |bytes_so_far| has been accurately hashed into |hash_state| and will | 91 // |offset| has been accurately hashed into |hash_state| and will |
81 // ignore |hash_so_far|. | 92 // ignore |hash_so_far|. Not used if |access_mode| is equal to SHARED. |
| 93 // |
| 94 // |access_mode|: Specifies whether the file is going to be accessed by |
| 95 // multiple writers. If so, it is possible that one writer can request |
| 96 // writing to a |offset| that is larger than the file size. |
82 DownloadInterruptReason Initialize( | 97 DownloadInterruptReason Initialize( |
83 const base::FilePath& full_path, | 98 const base::FilePath& full_path, |
84 const base::FilePath& default_directory, | 99 const base::FilePath& default_directory, |
85 base::File file, | 100 base::File file, |
86 int64_t bytes_so_far, | 101 int64_t offset, |
87 const std::string& hash_so_far, | 102 const std::string& hash_so_far, |
88 std::unique_ptr<crypto::SecureHash> hash_state); | 103 std::unique_ptr<crypto::SecureHash> hash_state, |
| 104 AccessMode access_mode); |
89 | 105 |
90 // Write a new chunk of data to the file. Returns a DownloadInterruptReason | 106 // Write a new chunk of data to the current |offset_| inside the file. Returns |
91 // indicating the result of the operation. | 107 // a DownloadInterruptReason indicating the result of the operation. |
92 DownloadInterruptReason AppendDataToFile(const char* data, size_t data_len); | 108 DownloadInterruptReason WriteDataToFile(const char* data, size_t data_len); |
93 | 109 |
94 // Rename the download file. Returns a DownloadInterruptReason indicating the | 110 // Rename the download file. Returns a DownloadInterruptReason indicating the |
95 // result of the operation. A return code of NONE indicates that the rename | 111 // result of the operation. A return code of NONE indicates that the rename |
96 // was successful. After a failure, the full_path() and in_progress() can be | 112 // was successful. After a failure, the full_path() and in_progress() can be |
97 // used to determine the last known filename and whether the file is available | 113 // used to determine the last known filename and whether the file is available |
98 // for writing or retrying the rename. Call Finish() to obtain the last known | 114 // for writing or retrying the rename. Call Finish() to obtain the last known |
99 // hash state. | 115 // hash state. |
100 DownloadInterruptReason Rename(const base::FilePath& full_path); | 116 DownloadInterruptReason Rename(const base::FilePath& full_path); |
101 | 117 |
102 // Mark the file as detached. Up until this method is called, BaseFile assumes | 118 // Mark the file as detached. Up until this method is called, BaseFile assumes |
(...skipping 27 matching lines...) Expand all Loading... |
130 const GURL& referrer_url); | 146 const GURL& referrer_url); |
131 | 147 |
132 // Returns the last known path to the download file. Can be empty if there's | 148 // Returns the last known path to the download file. Can be empty if there's |
133 // no file. | 149 // no file. |
134 const base::FilePath& full_path() const { return full_path_; } | 150 const base::FilePath& full_path() const { return full_path_; } |
135 | 151 |
136 // Returns true if the file is open. If true, the file can be written to or | 152 // Returns true if the file is open. If true, the file can be written to or |
137 // renamed. | 153 // renamed. |
138 bool in_progress() const { return file_.IsValid(); } | 154 bool in_progress() const { return file_.IsValid(); } |
139 | 155 |
140 // Returns the number of bytes in the file pointed to by full_path(). | 156 // Returns the number of bytes that has been written so far. If |access_mode_| |
| 157 // is EXCLUSIVE, this should always be equal to the file size. If |
| 158 // |access_mode_| is SHARED, this only records the byte that is written by |
| 159 // the current writer. So it is smaller than the file size as there are other |
| 160 // writers around. |
141 int64_t bytes_so_far() const { return bytes_so_far_; } | 161 int64_t bytes_so_far() const { return bytes_so_far_; } |
142 | 162 |
| 163 // Returns the current offset that data will be written to. |
| 164 int64_t offset() const { return offset_; } |
| 165 |
143 std::string DebugString() const; | 166 std::string DebugString() const; |
144 | 167 |
145 private: | 168 private: |
146 friend class BaseFileTest; | 169 friend class BaseFileTest; |
147 FRIEND_TEST_ALL_PREFIXES(BaseFileTest, IsEmptyHash); | 170 FRIEND_TEST_ALL_PREFIXES(BaseFileTest, IsEmptyHash); |
148 | 171 |
149 // Creates and opens the file_ if it is invalid. | 172 // Creates and opens the file_ if it is invalid. |
150 // | 173 // |
151 // If |hash_so_far| is not empty, then it must match the SHA-256 hash of the | 174 // If |access_mode_| is EXCLUSIVE and |hash_so_far| is not empty, then it must |
152 // first |bytes_so_far_| bytes of |file_|. If there's a hash mismatch, Open() | 175 // match the SHA-256 hash of the first |offset_| bytes of |file_|. If there's |
153 // fails with DOWNLOAD_INTERRUPT_REASON_FILE_HASH_MISMATCH. | 176 // a hash mismatch, Open() fails with |
| 177 // DOWNLOAD_INTERRUPT_REASON_FILE_HASH_MISMATCH. |
154 // | 178 // |
155 // If the opened file is shorter than |bytes_so_far_| bytes, then Open() fails | 179 // When |access_mode_| is EXCLUSIVE, If the opened file is shorter than |
156 // with DOWNLOAD_INTERRUPT_REASON_FILE_TOO_SHORT. If the opened file is | 180 // |offset_| bytes, then Open() fails with |
157 // longer, then the file is truncated to |bytes_so_far_|. | 181 // DOWNLOAD_INTERRUPT_REASON_FILE_TOO_SHORT. If the opened file is |
| 182 // longer, then the file is truncated to |offset_|. |
158 // | 183 // |
159 // Open() can fail for other reasons as well. In that case, it returns a | 184 // Open() can fail for other reasons as well. In that case, it returns a |
160 // relevant interrupt reason. Unless Open() return | 185 // relevant interrupt reason. Unless Open() return |
161 // DOWNLOAD_INTERRUPT_REASON_NONE, it should be assumed that |file_| is not | 186 // DOWNLOAD_INTERRUPT_REASON_NONE, it should be assumed that |file_| is not |
162 // valid. | 187 // valid. |
163 DownloadInterruptReason Open(const std::string& hash_so_far); | 188 DownloadInterruptReason Open(const std::string& hash_so_far); |
164 | 189 |
165 // Closes and resets file_. | 190 // Closes and resets file_. |
166 void Close(); | 191 void Close(); |
167 | 192 |
168 // Resets file_. | 193 // Resets file_. |
169 void ClearFile(); | 194 void ClearFile(); |
170 | 195 |
171 // Platform specific method that moves a file to a new path and adjusts the | 196 // Platform specific method that moves a file to a new path and adjusts the |
172 // security descriptor / permissions on the file to match the defaults for the | 197 // security descriptor / permissions on the file to match the defaults for the |
173 // new directory. | 198 // new directory. |
174 DownloadInterruptReason MoveFileAndAdjustPermissions( | 199 DownloadInterruptReason MoveFileAndAdjustPermissions( |
175 const base::FilePath& new_path); | 200 const base::FilePath& new_path); |
176 | 201 |
177 // Split out from CurrentSpeed to enable testing. | 202 // Split out from CurrentSpeed to enable testing. |
178 int64_t CurrentSpeedAtTime(base::TimeTicks current_time) const; | 203 int64_t CurrentSpeedAtTime(base::TimeTicks current_time) const; |
179 | 204 |
180 // Verifies that: | 205 // This function is only used when |access_mode_| is EXCLUSIVE. It verifies |
181 // * Size of the file represented by |file_| is at least |bytes_so_far_|. | 206 // that: |
| 207 // * Size of the file represented by |file_| is at least |offset_|. |
182 // | 208 // |
183 // * If |hash_to_expect| is not empty, then the result of hashing the first | 209 // * If |hash_to_expect| is not empty, then the result of hashing the first |
184 // |bytes_so_far_| bytes of |file_| matches |hash_to_expect|. | 210 // |offset_| bytes of |file_| matches |hash_to_expect|. |
185 // | 211 // |
186 // If the result is REASON_NONE, then on return |secure_hash_| is valid and | 212 // If the result is REASON_NONE, then on return |secure_hash_| is valid and |
187 // is ready to hash bytes from offset |bytes_so_far_| + 1. | 213 // is ready to hash bytes from offset |offset_| + 1. |
188 DownloadInterruptReason CalculatePartialHash( | 214 DownloadInterruptReason CalculatePartialHash( |
189 const std::string& hash_to_expect); | 215 const std::string& hash_to_expect); |
190 | 216 |
191 // Log a TYPE_DOWNLOAD_FILE_ERROR NetLog event with |error| and passes error | 217 // Log a TYPE_DOWNLOAD_FILE_ERROR NetLog event with |error| and passes error |
192 // on through, converting to a |DownloadInterruptReason|. | 218 // on through, converting to a |DownloadInterruptReason|. |
193 DownloadInterruptReason LogNetError(const char* operation, net::Error error); | 219 DownloadInterruptReason LogNetError(const char* operation, net::Error error); |
194 | 220 |
195 // Log the system error in |os_error| and converts it into a | 221 // Log the system error in |os_error| and converts it into a |
196 // |DownloadInterruptReason|. | 222 // |DownloadInterruptReason|. |
197 DownloadInterruptReason LogSystemError(const char* operation, | 223 DownloadInterruptReason LogSystemError(const char* operation, |
198 logging::SystemErrorCode os_error); | 224 logging::SystemErrorCode os_error); |
199 | 225 |
200 // Log a TYPE_DOWNLOAD_FILE_ERROR NetLog event with |os_error| and |reason|. | 226 // Log a TYPE_DOWNLOAD_FILE_ERROR NetLog event with |os_error| and |reason|. |
201 // Returns |reason|. | 227 // Returns |reason|. |
202 DownloadInterruptReason LogInterruptReason( | 228 DownloadInterruptReason LogInterruptReason( |
203 const char* operation, int os_error, | 229 const char* operation, int os_error, |
204 DownloadInterruptReason reason); | 230 DownloadInterruptReason reason); |
205 | 231 |
206 // Full path to the file including the file name. | 232 // Full path to the file including the file name. |
207 base::FilePath full_path_; | 233 base::FilePath full_path_; |
208 | 234 |
209 // OS file for writing | 235 // OS file for writing |
210 base::File file_; | 236 base::File file_; |
211 | 237 |
212 // Amount of data received up so far, in bytes. | 238 // Current byte offset to write the data. |
| 239 int64_t offset_ = 0; |
| 240 |
| 241 // Amount of data received up so far, in bytes. This should be equal to |
| 242 // |offset_| when |access_mode_| is EXCLUSIVE. If |access_mode_| is SHARED, |
| 243 // this only tracks the bytes received by the current writer. |
213 int64_t bytes_so_far_ = 0; | 244 int64_t bytes_so_far_ = 0; |
214 | 245 |
215 // Used to calculate hash for the file when calculate_hash_ is set. | 246 // Used to calculate hash for the file when calculate_hash_ is set. |
216 std::unique_ptr<crypto::SecureHash> secure_hash_; | 247 std::unique_ptr<crypto::SecureHash> secure_hash_; |
217 | 248 |
218 // Start time for calculating speed. | 249 // Start time for calculating speed. |
219 base::TimeTicks start_tick_; | 250 base::TimeTicks start_tick_; |
220 | 251 |
221 // Indicates that this class no longer owns the associated file, and so | 252 // Indicates that this class no longer owns the associated file, and so |
222 // won't delete it on destruction. | 253 // won't delete it on destruction. |
223 bool detached_ = false; | 254 bool detached_ = false; |
224 | 255 |
| 256 AccessMode access_mode_ = EXCLUSIVE; |
| 257 |
225 net::NetLogWithSource net_log_; | 258 net::NetLogWithSource net_log_; |
226 | 259 |
227 DISALLOW_COPY_AND_ASSIGN(BaseFile); | 260 DISALLOW_COPY_AND_ASSIGN(BaseFile); |
228 }; | 261 }; |
229 | 262 |
230 } // namespace content | 263 } // namespace content |
231 | 264 |
232 #endif // CONTENT_BROWSER_DOWNLOAD_BASE_FILE_H_ | 265 #endif // CONTENT_BROWSER_DOWNLOAD_BASE_FILE_H_ |
OLD | NEW |