File: base_file.h

package info (click to toggle)
chromium 139.0.7258.127-1
  • links: PTS, VCS
  • area: main
  • in suites:
  • size: 6,122,068 kB
  • sloc: cpp: 35,100,771; ansic: 7,163,530; javascript: 4,103,002; python: 1,436,920; asm: 946,517; xml: 746,709; pascal: 187,653; perl: 88,691; sh: 88,436; objc: 79,953; sql: 51,488; cs: 44,583; fortran: 24,137; makefile: 22,147; tcl: 15,277; php: 13,980; yacc: 8,984; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (323 lines) | stat: -rw-r--r-- 14,097 bytes parent folder | download | duplicates (9)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef COMPONENTS_DOWNLOAD_PUBLIC_COMMON_BASE_FILE_H_
#define COMPONENTS_DOWNLOAD_PUBLIC_COMMON_BASE_FILE_H_

#include <stddef.h>
#include <stdint.h>

#include <memory>
#include <string>

#include "base/check.h"
#include "base/files/file.h"
#include "base/files/file_path.h"
#include "base/functional/callback.h"
#include "base/functional/callback_forward.h"
#include "base/gtest_prod_util.h"
#include "base/memory/weak_ptr.h"
#include "base/sequence_checker.h"
#include "base/time/time.h"
#include "build/build_config.h"
#include "components/download/public/common/download_export.h"
#include "components/download/public/common/download_interrupt_reasons.h"
#include "components/services/quarantine/public/mojom/quarantine.mojom.h"
#include "crypto/secure_hash.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "mojo/public/cpp/bindings/remote.h"
#include "net/base/net_errors.h"
#include "url/gurl.h"
#include "url/origin.h"

namespace download {

// File being downloaded and saved to disk. This is a base class
// for DownloadFile and SaveFile, which keep more state information. BaseFile
// considers itself the owner of the physical file and will delete it when the
// BaseFile object is destroyed unless the ownership is revoked via a call to
// Detach().
class COMPONENTS_DOWNLOAD_EXPORT BaseFile {
 public:
  // Given a source and a referrer, determines the "safest" URL that can be used
  // to determine the authority of the download source. Returns an empty URL if
  // no HTTP/S URL can be determined for the <|source_url|, |referrer_url|>
  // pair.
  static GURL GetEffectiveAuthorityURL(const GURL& source_url,
                                       const GURL& referrer_url);

  // May be constructed on any thread.  All other routines (including
  // destruction) must occur on the same sequence.
  explicit BaseFile(uint32_t download_id);

  BaseFile(const BaseFile&) = delete;
  BaseFile& operator=(const BaseFile&) = delete;

  ~BaseFile();

  // Returns DOWNLOAD_INTERRUPT_REASON_NONE on success, or a
  // DownloadInterruptReason on failure. Upon success, the file at |full_path()|
  // is assumed to be owned by the BaseFile. It will be deleted when the
  // BaseFile object is destroyed unless Detach() is called before destroying
  // the BaseFile instance.
  //
  // |full_path|: Full path to the download file. Can be empty, in which case
  //     the rules described in |default_directory| will be used to generate a
  //     temporary filename.
  //
  // |default_directory|: specifies the directory to create the temporary file
  //     in if |full_path| is empty. If |default_directory| and |full_path| are
  //     empty, then a temporary file will be created in the default download
  //     location as determined by ContentBrowserClient.
  //
  // |file|: The base::File handle to use. If specified, BaseFile will not open
  //     a file and will use this handle. The file should be opened for both
  //     read and write. Only makes sense if |full_path| is non-empty since it
  //     implies that the caller already knows the path to the file.  There's no
  //     perfect way to come up with a canonical path for a file. So BaseFile
  //     will not attempt to determine the |full_path|.
  //
  // |bytes_so_far|: If a file is provided (via |full_path| or |file|), then
  //     this argument specifies the amount of data that has been written to
  //     the file. If |is_sparse_file| is false, this value should be the size
  //     of the file to expect. It is legal for the file to be larger, in which
  //     case the file will be truncated down to this size if |is_sparse_file|
  //     is false. However, if the file is shorter, then the operation will
  //     fail with DOWNLOAD_INTERRUPT_REASON_FILE_TOO_SHORT.

  //
  // |hash_so_far|: If |bytes_so_far| is non-zero and |is_sparse_file| is
  //     false, this specifies the SHA-256 hash of the first |bytes_so_far|
  //     bytes of the target file. If specified, BaseFile will read the first
  //     |bytes_so_far| of the target file in order to calculate the hash and
  //     verify that the file matches. If there's a mismatch, then the operation
  //     fails with DOWNLOAD_INTERRUPT_REASON_FILE_HASH_MISMATCH. Not used if
  //     |hash_state| is also specified.
  //
  // |hash_state|: The partial hash object to use. Only meaningful if there's a
  //     preexisting target file and it is non-empty (i.e. bytes_so_far is
  //     non-zero). If specified, BaseFile will assume that the bytes up to
  //     |bytes_so_far| has been accurately hashed into |hash_state| and will
  //     ignore |hash_so_far|. Not used if |is_sparse_file| is true.
  //
  // |is_sparse_file|: Specifies whether the file is a sparse file. If so, it is
  //     possible that a write can happen at an offset that is larger than the
  //     file size, thus creating holes in it.
  //
  // |bytes_wasted|: Address of an integer that will handle bytes_wasted if
  //     there is a significant amount (ie. greater than 0).
  DownloadInterruptReason Initialize(
      const base::FilePath& full_path,
      const base::FilePath& default_directory,
      base::File file,
      int64_t bytes_so_far,
      const std::string& hash_so_far,
      std::unique_ptr<crypto::SecureHash> hash_state,
      bool is_sparse_file,
      int64_t* const bytes_wasted);

  // Write a new chunk of data to the file. Returns a DownloadInterruptReason
  // indicating the result of the operation. Works only if |is_sparse_file| is
  // false.
  DownloadInterruptReason AppendDataToFile(const char* data, size_t data_len);

  // Write a new chunk of data to the file. Returns a DownloadInterruptReason
  // indicating the result of the operation.
  DownloadInterruptReason WriteDataToFile(int64_t offset,
                                          const char* data,
                                          size_t data_len);

  // Validates that the content starting from |offset| matches that of |data|
  // with the given length.
  bool ValidateDataInFile(int64_t offset, const char* data, size_t data_len);

  // Rename the download file. Returns a DownloadInterruptReason indicating the
  // result of the operation. A return code of NONE indicates that the rename
  // was successful. After a failure, the full_path() and in_progress() can be
  // used to determine the last known filename and whether the file is available
  // for writing or retrying the rename. Call Finish() to obtain the last known
  // hash state.
  DownloadInterruptReason Rename(const base::FilePath& full_path);

  // Mark the file as detached. Up until this method is called, BaseFile assumes
  // ownership of the file and hence will delete the file if the BaseFile object
  // is destroyed. Calling Detach() causes BaseFile to assume that it no longer
  // owns the file. Detach() can be called at any time. Close() must still be
  // called to close the file if it is open.
  void Detach();

  // Abort the download and automatically close and delete the file.
  void Cancel();

  // Indicate that the download has finished. No new data will be received.
  // Returns the SecureHash object representing the state of the hash function
  // at the end of the operation. If |is_sparse_file_| is true, calling this
  // will cause |secure_hash_| to get calculated.
  std::unique_ptr<crypto::SecureHash> Finish();

  // Callback used with AnnotateWithSourceInformation.
  // Created by DownloadFileImpl::RenameWithRetryInternal
  // to bind DownloadFileImpl::OnRenameComplete.
  using OnAnnotationDoneCallback =
      base::OnceCallback<void(DownloadInterruptReason)>;

  // Informs the OS that this file came from the internet. Calls
  // |on_annotation_done_callback| with DownloadInterruptReason indicating the
  // result of the operation.
  //
  // |client_guid|: The client GUID which will be used to identify the caller to
  //     the system AV scanning function.
  //
  // |source_url| / |referrer_url|: Source and referrer for the network request
  //     that originated this download. Will be used to annotate source
  //     information and also to determine the relative danger level of the
  //     file.
  //
  // `request_initiator`: Initiating origin for the request. This will
  //     be used in place of the `source_url` when the `source_url` is not
  //     suitable for reporting to the OS.
  void AnnotateWithSourceInformation(
      const std::string& client_guid,
      const GURL& source_url,
      const GURL& referrer_url,
      const std::optional<url::Origin>& request_initiator,
      mojo::PendingRemote<quarantine::mojom::Quarantine> remote_quarantine,
      OnAnnotationDoneCallback on_annotation_done_callback);

#if BUILDFLAG(IS_ANDROID)
  // Publishes the intermediate download to public download collection.
  DownloadInterruptReason PublishDownload();
#endif

  // Returns the last known path to the download file. Can be empty if there's
  // no file.
  const base::FilePath& full_path() const { return full_path_; }

  // Returns true if the file is open. If true, the file can be written to or
  // renamed.
  bool in_progress() const { return file_.IsValid(); }

  // Returns the number of bytes that has been written so far. If
  // |is_sparse_file_| is false, this should always be equal to the file size.
  // If |is_sparse_file_| is true, this should not be larger than the file size
  // as the file may contain holes in it.
  int64_t bytes_so_far() const { return bytes_so_far_; }

  std::string DebugString() const;

 private:
  friend class BaseFileTest;
  FRIEND_TEST_ALL_PREFIXES(BaseFileTest, IsEmptyHash);

  // Creates and opens the file_ if it is invalid.
  //
  // If |is_sparse_file_| is false and |hash_so_far| is not empty, then it must
  // match the SHA-256 hash of the first |bytes_so_far_| bytes of |file_|. If
  // there's a hash mismatch, Open() fails with
  // DOWNLOAD_INTERRUPT_REASON_FILE_HASH_MISMATCH.
  //
  // If the opened file is shorter than |bytes_so_far_| bytes, then Open() fails
  // with DOWNLOAD_INTERRUPT_REASON_FILE_TOO_SHORT. If the opened file is longer
  // and |is_sparse_file_| is false, then the file is truncated to
  // |bytes_so_far_|.
  //
  // Open() can fail for other reasons as well. In that case, it returns a
  // relevant interrupt reason. Unless Open() return
  // DOWNLOAD_INTERRUPT_REASON_NONE, it should be assumed that |file_| is not
  // valid.
  DownloadInterruptReason Open(const std::string& hash_so_far,
                               int64_t* const bytes_wasted);

  // Closes and resets file_.
  void Close();

  // Resets file_.
  void ClearFile();

  // Platform specific method that moves a file to a new path and adjusts the
  // security descriptor / permissions on the file to match the defaults for the
  // new directory.
  DownloadInterruptReason MoveFileAndAdjustPermissions(
      const base::FilePath& new_path);

  // Split out from CurrentSpeed to enable testing.
  int64_t CurrentSpeedAtTime(base::TimeTicks current_time) const;

  // Verifies that:
  // * Size of the file represented by |file_| is at least |bytes_so_far_|.
  //
  // * If |hash_to_expect| is not empty, then the result of hashing the first
  //   |bytes_so_far_| bytes of |file_| matches |hash_to_expect|.
  //
  // If the result is REASON_NONE, then on return |secure_hash_| is valid and
  // is ready to hash bytes from offset |bytes_so_far_| + 1.
  // If |is_sparse_file_| is true, this function is only called when Finish()
  // is called.
  DownloadInterruptReason CalculatePartialHash(
      const std::string& hash_to_expect);

  // Log a TYPE_DOWNLOAD_FILE_ERROR NetLog event with |error| and passes error
  // on through, converting to a |DownloadInterruptReason|.
  DownloadInterruptReason LogNetError(const char* operation, net::Error error);

  // Log the system error in |os_error| and converts it into a
  // |DownloadInterruptReason|.
  DownloadInterruptReason LogSystemError(const char* operation,
                                         logging::SystemErrorCode os_error);

  // Log a TYPE_DOWNLOAD_FILE_ERROR NetLog event with |os_error| and |reason|.
  // Returns |reason|.
  DownloadInterruptReason LogInterruptReason(const char* operation,
                                             int os_error,
                                             DownloadInterruptReason reason);

  // Callback invoked when quarantine service has an error.
  void OnQuarantineServiceError(const GURL& source_url,
                                const GURL& referrer_url);

  // Callback invoked by quarantine service. Also called by
  // OnQuarantineServiceError after manually applying mark-of-the-web.
  void OnFileQuarantined(quarantine::mojom::QuarantineFileResult result);

  // Full path to the file including the file name.
  base::FilePath full_path_;

  // OS file for writing
  base::File file_;

  // Amount of data received up so far, in bytes.
  int64_t bytes_so_far_ = 0;

  // Used to calculate hash for the file when calculate_hash_ is set.
  std::unique_ptr<crypto::SecureHash> secure_hash_;

  // Start time for calculating speed.
  base::TimeTicks start_tick_;

  // Indicates that this class no longer owns the associated file, and so
  // won't delete it on destruction.
  bool detached_ = false;

  // Whether the file is sparse.
  // TODO(qinmin): pass the slice information to this class so that we can
  // verify that writes are not overlapping.
  bool is_sparse_file_ = false;

  // ID of the download, used for trace events.
  uint32_t download_id_;

  // Mojo remote for quarantine service.
  mojo::Remote<quarantine::mojom::Quarantine> quarantine_service_;

  // Callback invoked after quarantine service finishes.
  OnAnnotationDoneCallback on_annotation_done_callback_;

  SEQUENCE_CHECKER(sequence_checker_);

  base::WeakPtrFactory<BaseFile> weak_factory_{this};
};

}  // namespace download

#endif  // COMPONENTS_DOWNLOAD_PUBLIC_COMMON_BASE_FILE_H_