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_
|