blob: 8617556dbfb2db9d220184fc42118262bf7fb42d [file] [log] [blame]
// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef STORAGE_BROWSER_FILEAPI_FILE_SYSTEM_OPERATION_RUNNER_H_
#define STORAGE_BROWSER_FILEAPI_FILE_SYSTEM_OPERATION_RUNNER_H_
#include <stdint.h>
#include <map>
#include <memory>
#include <set>
#include <vector>
#include "base/containers/id_map.h"
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
#include "components/services/filesystem/public/interfaces/types.mojom.h"
#include "storage/browser/blob/blob_data_handle.h"
#include "storage/browser/fileapi/file_system_operation.h"
#include "storage/browser/fileapi/file_system_url.h"
#include "storage/browser/storage_browser_export.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.
// All operation methods return kErrorOperationID if running (posting) an
// operation fails, in addition to dispatching the callback with an error
// code (therefore in most cases the caller does not need to check the
// returned operation ID).
class STORAGE_EXPORT FileSystemOperationRunner {
public:
using GetMetadataCallback = FileSystemOperation::GetMetadataCallback;
using ReadDirectoryCallback = FileSystemOperation::ReadDirectoryCallback;
using SnapshotFileCallback = FileSystemOperation::SnapshotFileCallback;
using StatusCallback = FileSystemOperation::StatusCallback;
using WriteCallback = FileSystemOperation::WriteCallback;
using OpenFileCallback = FileSystemOperation::OpenFileCallback;
using ErrorBehavior = FileSystemOperation::ErrorBehavior;
using CopyProgressCallback = FileSystemOperation::CopyProgressCallback;
using CopyFileProgressCallback =
FileSystemOperation::CopyFileProgressCallback;
using CopyOrMoveOption = FileSystemOperation::CopyOrMoveOption;
using GetMetadataField = FileSystemOperation::GetMetadataField;
using OperationID = int;
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 |progress_callback|, see file_system_operation.h for
// details.
OperationID Copy(const FileSystemURL& src_url,
const FileSystemURL& dest_url,
CopyOrMoveOption option,
ErrorBehavior error_behavior,
const CopyProgressCallback& progress_callback,
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|, see file_system_operation.h for details.
OperationID Move(const FileSystemURL& src_url,
const FileSystemURL& dest_url,
CopyOrMoveOption option,
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,
int 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<storage::BlobDataHandle> blob,
int64_t offset,
const WriteCallback& callback);
// Writes contents of |data_pipe| to |url| at |offset|.
OperationID Write(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::PlatformFileFlags.
//
// |peer_handle| is the process handle of a pepper plugin process, which
// is necessary for underlying IPC calls with Pepper plugins.
//
// This function is used only by Pepper as of writing.
OperationID OpenFile(const FileSystemURL& url,
int 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 implementaiton 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,
CopyOrMoveOption option,
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,
CopyOrMoveOption option,
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:
friend class FileSystemContext;
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<storage::ShareableFileReference> file_ref);
void OnCopyProgress(const OperationID id,
const CopyProgressCallback& callback,
FileSystemOperation::CopyProgressType type,
const FileSystemURL& source_url,
const FileSystemURL& dest_url,
int64_t size);
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; file_system_context owns this.
FileSystemContext* 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_;
DISALLOW_COPY_AND_ASSIGN(FileSystemOperationRunner);
};
} // namespace storage
#endif // STORAGE_BROWSER_FILEAPI_FILE_SYSTEM_OPERATION_RUNNER_H_