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 324 325 326 327 328 329 330 331 332 333
|
// Copyright 2013 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef STORAGE_BROWSER_FILE_SYSTEM_FILE_SYSTEM_OPERATION_RUNNER_H_
#define STORAGE_BROWSER_FILE_SYSTEM_FILE_SYSTEM_OPERATION_RUNNER_H_
#include <stdint.h>
#include <map>
#include <memory>
#include <set>
#include <vector>
#include "base/component_export.h"
#include "base/containers/id_map.h"
#include "base/functional/callback_helpers.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/types/pass_key.h"
#include "components/services/filesystem/public/mojom/types.mojom.h"
#include "storage/browser/blob/blob_data_handle.h"
#include "storage/browser/file_system/file_system_operation.h"
#include "storage/browser/file_system/file_system_url.h"
namespace storage {
class FileSystemURL;
class FileSystemContext;
// A central interface for running FileSystem API operations.
// All operation methods take callback and returns OperationID, which is
// an integer value which can be used for cancelling an operation.
class COMPONENT_EXPORT(STORAGE_BROWSER) FileSystemOperationRunner {
public:
using GetMetadataCallback = FileSystemOperation::GetMetadataCallback;
using ReadDirectoryCallback = FileSystemOperation::ReadDirectoryCallback;
using SnapshotFileCallback = FileSystemOperation::SnapshotFileCallback;
using StatusCallback = FileSystemOperation::StatusCallback;
using WriteCallback = FileSystemOperation::WriteCallback;
// Implementers of FileSystemOperation::OpenFile() pass `on_close_callback` as
// a OnceClosure, but pass consumers a ScopedClosureRunner to ensure the
// callback is always run, and on the correct sequence (the I/O thread).
using OpenFileCallback =
base::OnceCallback<void(base::File file,
base::ScopedClosureRunner on_close_callback)>;
using ErrorBehavior = FileSystemOperation::ErrorBehavior;
using CopyFileProgressCallback =
FileSystemOperation::CopyFileProgressCallback;
using CopyOrMoveOptionSet = FileSystemOperation::CopyOrMoveOptionSet;
using GetMetadataField = FileSystemOperation::GetMetadataField;
using GetMetadataFieldSet = FileSystemOperation::GetMetadataFieldSet;
using OperationID = uint64_t;
// |file_system_context| is stored as a raw pointer. The caller must ensure
// that |file_system_context| outlives the new instance.
FileSystemOperationRunner(
base::PassKey<FileSystemContext>,
const scoped_refptr<FileSystemContext>& file_system_context);
FileSystemOperationRunner(base::PassKey<FileSystemContext>,
FileSystemContext* file_system_context);
FileSystemOperationRunner(const FileSystemOperationRunner&) = delete;
FileSystemOperationRunner& operator=(const FileSystemOperationRunner&) =
delete;
virtual ~FileSystemOperationRunner();
// Cancels all inflight operations.
void Shutdown();
// Creates a file at |url|. If |exclusive| is true, an error is raised
// in case a file is already present at the URL.
OperationID CreateFile(const FileSystemURL& url,
bool exclusive,
StatusCallback callback);
OperationID CreateDirectory(const FileSystemURL& url,
bool exclusive,
bool recursive,
StatusCallback callback);
// Copies a file or directory from |src_url| to |dest_url|. If
// |src_url| is a directory, the contents of |src_url| are copied to
// |dest_url| recursively. A new file or directory is created at
// |dest_url| as needed.
// For |option| and |copy_or_move_hook_delegate|, see file_system_operation.h
// for details.
OperationID Copy(
const FileSystemURL& src_url,
const FileSystemURL& dest_url,
CopyOrMoveOptionSet options,
ErrorBehavior error_behavior,
std::unique_ptr<CopyOrMoveHookDelegate> copy_or_move_hook_delegate,
StatusCallback callback);
// Moves a file or directory from |src_url| to |dest_url|. A new file
// or directory is created at |dest_url| as needed.
// For |option| and |copy_or_move_hook_delegate|, see file_system_operation.h
// for details.
OperationID Move(
const FileSystemURL& src_url,
const FileSystemURL& dest_url,
CopyOrMoveOptionSet options,
ErrorBehavior error_behavior,
std::unique_ptr<CopyOrMoveHookDelegate> copy_or_move_hook_delegate,
StatusCallback callback);
// Checks if a directory is present at |url|.
OperationID DirectoryExists(const FileSystemURL& url,
StatusCallback callback);
// Checks if a file is present at |url|.
OperationID FileExists(const FileSystemURL& url, StatusCallback callback);
// Gets the metadata of a file or directory at |url|.
OperationID GetMetadata(const FileSystemURL& url,
GetMetadataFieldSet fields,
GetMetadataCallback callback);
// Reads contents of a directory at |url|.
OperationID ReadDirectory(const FileSystemURL& url,
const ReadDirectoryCallback& callback);
// Removes a file or directory at |url|. If |recursive| is true, remove
// all files and directories under the directory at |url| recursively.
OperationID Remove(const FileSystemURL& url,
bool recursive,
StatusCallback callback);
// Writes contents of |blob| to |url| at |offset|.
OperationID Write(const FileSystemURL& url,
std::unique_ptr<BlobDataHandle> blob,
int64_t offset,
const WriteCallback& callback);
// Writes contents of |data_pipe| to |url| at |offset|.
OperationID WriteStream(const FileSystemURL& url,
mojo::ScopedDataPipeConsumerHandle data_pipe,
int64_t offset,
const WriteCallback& callback);
// Truncates a file at |url| to |length|. If |length| is larger than
// the original file size, the file will be extended, and the extended
// part is filled with null bytes.
OperationID Truncate(const FileSystemURL& url,
int64_t length,
StatusCallback callback);
// Tries to cancel the operation |id| [we support cancelling write or
// truncate only]. Reports failure for the current operation, then reports
// success for the cancel operation itself via the |callback|.
void Cancel(OperationID id, StatusCallback callback);
// Modifies timestamps of a file or directory at |url| with
// |last_access_time| and |last_modified_time|. The function DOES NOT
// create a file unlike 'touch' command on Linux.
//
// This function is used only by Pepper as of writing.
OperationID TouchFile(const FileSystemURL& url,
const base::Time& last_access_time,
const base::Time& last_modified_time,
StatusCallback callback);
// Opens a file at |url| with |file_flags|, where flags are OR'ed values of
// base::File::Flags. This operation is not supported on all filesystems or
// all situation e.g. it will always fail for the sandboxed system when in
// Incognito mode.
OperationID OpenFile(const FileSystemURL& url,
uint32_t file_flags,
OpenFileCallback callback);
// Creates a local snapshot file for a given |url| and returns the
// metadata and platform url of the snapshot file via |callback|.
// In local filesystem cases the implementation may simply return
// the metadata of the file itself (as well as GetMetadata does),
// while in remote filesystem case the backend may want to download the file
// into a temporary snapshot file and return the metadata of the
// temporary file. Or if the implementation already has the local cache
// data for |url| it can simply return the url to the cache.
OperationID CreateSnapshotFile(const FileSystemURL& url,
SnapshotFileCallback callback);
// Copies in a single file from a different filesystem.
//
// This returns:
// - File::FILE_ERROR_NOT_FOUND if |src_file_path|
// or the parent directory of |dest_url| does not exist.
// - File::FILE_ERROR_INVALID_OPERATION if |dest_url| exists and
// is not a file.
// - File::FILE_ERROR_FAILED if |dest_url| does not exist and
// its parent path is a file.
//
OperationID CopyInForeignFile(const base::FilePath& src_local_disk_path,
const FileSystemURL& dest_url,
StatusCallback callback);
// Removes a single file.
//
// This returns:
// - File::FILE_ERROR_NOT_FOUND if |url| does not exist.
// - File::FILE_ERROR_NOT_A_FILE if |url| is not a file.
//
OperationID RemoveFile(const FileSystemURL& url, StatusCallback callback);
// Removes a single empty directory.
//
// This returns:
// - File::FILE_ERROR_NOT_FOUND if |url| does not exist.
// - File::FILE_ERROR_NOT_A_DIRECTORY if |url| is not a directory.
// - File::FILE_ERROR_NOT_EMPTY if |url| is not empty.
//
OperationID RemoveDirectory(const FileSystemURL& url,
StatusCallback callback);
// Copies a file from |src_url| to |dest_url|.
// This must be called for files that belong to the same filesystem
// (i.e. type() and origin() of the |src_url| and |dest_url| must match).
// For |option| and |progress_callback|, see file_system_operation.h for
// details.
//
// This returns:
// - File::FILE_ERROR_NOT_FOUND if |src_url|
// or the parent directory of |dest_url| does not exist.
// - File::FILE_ERROR_NOT_A_FILE if |src_url| exists but is not a file.
// - File::FILE_ERROR_INVALID_OPERATION if |dest_url| exists and
// is not a file.
// - File::FILE_ERROR_FAILED if |dest_url| does not exist and
// its parent path is a file.
//
OperationID CopyFileLocal(const FileSystemURL& src_url,
const FileSystemURL& dest_url,
CopyOrMoveOptionSet options,
const CopyFileProgressCallback& progress_callback,
StatusCallback callback);
// Moves a local file from |src_url| to |dest_url|.
// This must be called for files that belong to the same filesystem
// (i.e. type() and origin() of the |src_url| and |dest_url| must match).
// For |option|, see file_system_operation.h for details.
//
// This returns:
// - File::FILE_ERROR_NOT_FOUND if |src_url|
// or the parent directory of |dest_url| does not exist.
// - File::FILE_ERROR_NOT_A_FILE if |src_url| exists but is not a file.
// - File::FILE_ERROR_INVALID_OPERATION if |dest_url| exists and
// is not a file.
// - File::FILE_ERROR_FAILED if |dest_url| does not exist and
// its parent path is a file.
//
OperationID MoveFileLocal(const FileSystemURL& src_url,
const FileSystemURL& dest_url,
CopyOrMoveOptionSet options,
StatusCallback callback);
// This is called only by pepper plugin as of writing to synchronously get
// the underlying platform path to upload a file in the sandboxed filesystem
// (e.g. TEMPORARY or PERSISTENT).
base::File::Error SyncGetPlatformPath(const FileSystemURL& url,
base::FilePath* platform_path);
private:
explicit FileSystemOperationRunner(FileSystemContext* file_system_context);
void DidFinish(const OperationID id,
StatusCallback callback,
base::File::Error rv);
void DidGetMetadata(const OperationID id,
GetMetadataCallback callback,
base::File::Error rv,
const base::File::Info& file_info);
void DidReadDirectory(const OperationID id,
const ReadDirectoryCallback& callback,
base::File::Error rv,
std::vector<filesystem::mojom::DirectoryEntry> entries,
bool has_more);
void DidWrite(const OperationID id,
const WriteCallback& callback,
base::File::Error rv,
int64_t bytes,
bool complete);
void DidOpenFile(const OperationID id,
OpenFileCallback callback,
base::File file,
base::OnceClosure on_close_callback);
void DidCreateSnapshot(const OperationID id,
SnapshotFileCallback callback,
base::File::Error rv,
const base::File::Info& file_info,
const base::FilePath& platform_path,
scoped_refptr<ShareableFileReference> file_ref);
void PrepareForWrite(OperationID id, const FileSystemURL& url);
void PrepareForRead(OperationID id, const FileSystemURL& url);
// These must be called at the beginning and end of any async operations.
OperationID BeginOperation(std::unique_ptr<FileSystemOperation> operation);
// Cleans up the FileSystemOperation for |id|, which may result in the
// FileSystemContext, and |this| being deleted, by the time the call returns.
void FinishOperation(OperationID id);
// Not owned; whatever owns this has to make sure context outlives this.
raw_ptr<FileSystemContext, AcrossTasksDanglingUntriaged> file_system_context_;
using Operations =
std::map<OperationID, std::unique_ptr<FileSystemOperation>>;
OperationID next_operation_id_ = 1;
Operations operations_;
// Used to detect synchronous invocation of completion callbacks by the
// back-end, to re-post them to be notified asynchronously. Note that some
// operations are recursive, so this may already be true when BeginOperation
// is called.
bool is_beginning_operation_ = false;
// We keep track of the file to be modified by each operation so that
// we can notify observers when we're done.
std::map<OperationID, FileSystemURLSet> write_target_urls_;
// Operations that are finished but not yet fire their callbacks.
std::set<OperationID> finished_operations_;
// Callbacks for stray cancels whose target operation is already finished.
std::map<OperationID, StatusCallback> stray_cancel_callbacks_;
base::WeakPtr<FileSystemOperationRunner> weak_ptr_;
base::WeakPtrFactory<FileSystemOperationRunner> weak_factory_{this};
};
} // namespace storage
#endif // STORAGE_BROWSER_FILE_SYSTEM_FILE_SYSTEM_OPERATION_RUNNER_H_
|