File: download_path_reservation_tracker.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 (141 lines) | stat: -rw-r--r-- 6,361 bytes parent folder | download | duplicates (11)
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
// 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_DOWNLOAD_PATH_RESERVATION_TRACKER_H_
#define COMPONENTS_DOWNLOAD_PUBLIC_COMMON_DOWNLOAD_PATH_RESERVATION_TRACKER_H_

#include "base/functional/callback_forward.h"
#include "base/memory/ref_counted.h"
#include "components/download/public/common/download_export.h"

namespace base {
class FilePath;
class SequencedTaskRunner;
}  // namespace base

namespace download {
class DownloadItem;

// Used in UMA, do not remove, change or reuse existing entries.
// Update histograms.xml and enums.xml when adding entries.
enum class PathValidationResult {
  SUCCESS = 0,
  PATH_NOT_WRITABLE,
  NAME_TOO_LONG,
  CONFLICT,
  SAME_AS_SOURCE,
  // There was a conflict, but it was successfully resolved via uniquification.
  // This should typically be treated like a success, except when the user
  // must decide to keep the uniquified file or cancel the download.
  SUCCESS_RESOLVED_CONFLICT,
  COUNT,
};

inline bool IsPathValidationSuccessful(PathValidationResult result) {
  return result == PathValidationResult::SUCCESS ||
         result == PathValidationResult::SUCCESS_RESOLVED_CONFLICT;
}

// Chrome attempts to uniquify filenames that are assigned to downloads in order
// to avoid overwriting files that already exist on the file system. Downloads
// that are considered potentially dangerous use random intermediate filenames.
// Therefore only considering files that exist on the filesystem is
// insufficient. This class tracks files that are assigned to active downloads
// so that uniquification can take those into account as well.
class COMPONENTS_DOWNLOAD_EXPORT DownloadPathReservationTracker {
 public:
  // Callback used with |GetReservedPath|. |target_path| specifies the target
  // path for the download. If |result| is SUCCESS or SUCCESS_RESOLVED_CONFLICT
  // then:
  // - |requested_target_path| (passed into GetReservedPath()) was writeable.
  // - |target_path| was verified as being unique if uniqueness was
  //   required.
  //
  // If |requested_target_path| was not writeable, then the parent directory of
  // |target_path| may be different from that of |requested_target_path|.
  using ReservedPathCallback =
      base::OnceCallback<void(PathValidationResult result,
                              const base::FilePath& target_path)>;

  // The largest index for the uniquification suffix that we will try while
  // attempting to come up with a unique path.
  static const int kMaxUniqueFiles = 100;

  enum FilenameConflictAction {
    UNIQUIFY,
    OVERWRITE,
    PROMPT,
  };

  // When a path needs to be assigned to a download, this method is called on
  // the UI thread along with a reference to the download item that will
  // eventually receive the reserved path. This method creates a path
  // reservation that will live until |download_item| is interrupted, cancelled,
  // completes or is removed. This method will not modify |download_item|.
  //
  // The process of issuing a reservation happens on the task runner returned by
  // DownloadPathReservationTracker::GetTaskRunner(), and involves:
  //
  // - Creating |requested_target_path.DirName()| if it doesn't already exist
  //   and either |create_directory| or |requested_target_path.DirName() ==
  //   default_download_path|.
  //
  // - Verifying that |requested_target_path| is writeable. If not,
  //   |fallback_directory| is used instead.
  //
  // - Uniquifying |requested_target_path| by suffixing the filename with a
  //   uniquifier (e.g. "foo.txt" -> "foo (1).txt") in order to avoid conflicts
  //   with files that already exist on the file system or other download path
  //   reservations. Uniquifying is only done if |conflict_action| is UNIQUIFY.
  //
  // - Posting a task back to the UI thread to invoke |completion_callback| with
  //   the reserved path and a bool indicating whether the returned path was
  //   verified as being writeable and unique.
  //
  // In addition, if the target path of |download_item| is changed to a path
  // other than the reserved path, then the reservation will be updated to
  // match. Such changes can happen if a "Save As" dialog was displayed and the
  // user chose a different path. The new target path is not checked against
  // active paths to enforce uniqueness. It is only used for uniquifying new
  // reservations.
  //
  // Once |completion_callback| is invoked, it is the caller's responsibility to
  // handle cases where the target path could not be verified and set the target
  // path of the |download_item| appropriately.
  //
  // The current implementation doesn't look at symlinks/mount points. E.g.: It
  // considers 'foo/bar/x.pdf' and 'foo/baz/x.pdf' to be two different paths,
  // even though 'bar' might be a symlink to 'baz'.
  static void GetReservedPath(DownloadItem* download_item,
                              const base::FilePath& requested_target_path,
                              const base::FilePath& default_download_path,
                              const base::FilePath& fallback_directory,
                              bool create_directory,
                              FilenameConflictAction conflict_action,
                              ReservedPathCallback callback);

  // Returns true if |path| is in use by an existing path reservation. Should
  // only be called on the task runner returned by
  // DownloadPathReservationTracker::GetTaskRunner(). Currently only used by
  // tests.
  static bool IsPathInUseForTesting(const base::FilePath& path);

  using CheckDownloadPathCallback =
      base::OnceCallback<void(bool /* file_exists */)>;

  // Checks to see if there is an existing path reservation that is separate
  // from the |download_item|, and calls |callback| with the result. Called by
  // ChromeDownloadManagerDelegate::OnDownloadTargetDetermined to see if there
  // is a target collision.
  static void CheckDownloadPathForExistingDownload(
      const base::FilePath& target_path,
      DownloadItem* download_item,
      CheckDownloadPathCallback callback);

  static scoped_refptr<base::SequencedTaskRunner> GetTaskRunner();
};

}  // namespace download

#endif  // COMPONENTS_DOWNLOAD_PUBLIC_COMMON_DOWNLOAD_PATH_RESERVATION_TRACKER_H_