| // 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. |
| |
| #include "storage/browser/file_system/file_system_operation_impl.h" |
| |
| #include <stdint.h> |
| |
| #include <limits> |
| #include <memory> |
| #include <tuple> |
| #include <utility> |
| |
| #include "base/functional/bind.h" |
| #include "base/functional/callback.h" |
| #include "base/functional/callback_helpers.h" |
| #include "base/task/sequenced_task_runner.h" |
| #include "base/time/time.h" |
| #include "base/types/pass_key.h" |
| #include "storage/browser/file_system/async_file_util.h" |
| #include "storage/browser/file_system/copy_or_move_hook_delegate.h" |
| #include "storage/browser/file_system/copy_or_move_operation_delegate.h" |
| #include "storage/browser/file_system/file_observers.h" |
| #include "storage/browser/file_system/file_system_backend.h" |
| #include "storage/browser/file_system/file_system_context.h" |
| #include "storage/browser/file_system/file_system_file_util.h" |
| #include "storage/browser/file_system/remove_operation_delegate.h" |
| #include "storage/browser/file_system/sandbox_file_system_backend_delegate.h" |
| #include "storage/browser/quota/quota_manager_proxy.h" |
| #include "storage/common/file_system/file_system_types.h" |
| #include "third_party/blink/public/common/storage_key/storage_key.h" |
| |
| namespace storage { |
| |
| namespace { |
| |
| // Takes ownership and destruct on the target thread. |
| void Destruct(base::File file) {} |
| |
| void DidOpenFile(scoped_refptr<FileSystemContext> context, |
| base::WeakPtr<FileSystemOperationImpl> operation, |
| FileSystemOperationImpl::OpenFileCallback callback, |
| base::File file, |
| base::OnceClosure on_close_callback) { |
| if (!operation) { |
| context->default_file_task_runner()->PostTask( |
| FROM_HERE, base::BindOnce(&Destruct, std::move(file))); |
| return; |
| } |
| std::move(callback).Run(std::move(file), std::move(on_close_callback)); |
| } |
| |
| } // namespace |
| |
| std::unique_ptr<FileSystemOperation> FileSystemOperation::Create( |
| OperationType type, |
| const FileSystemURL& url, |
| FileSystemContext* file_system_context, |
| std::unique_ptr<FileSystemOperationContext> operation_context) { |
| return std::make_unique<FileSystemOperationImpl>( |
| type, url, file_system_context, std::move(operation_context), |
| base::PassKey<FileSystemOperation>()); |
| } |
| |
| FileSystemOperationImpl::~FileSystemOperationImpl() = default; |
| |
| void FileSystemOperationImpl::CreateFile(const FileSystemURL& url, |
| bool exclusive, |
| StatusCallback callback) { |
| CheckOperationType(OperationType::kCreateFile); |
| |
| auto split_callback = base::SplitOnceCallback(std::move(callback)); |
| GetBucketSpaceRemainingAndRunTask( |
| url, |
| base::BindOnce(&FileSystemOperationImpl::DoCreateFile, |
| weak_factory_.GetWeakPtr(), url, |
| std::move(split_callback.first), exclusive), |
| base::BindOnce(std::move(split_callback.second), |
| base::File::FILE_ERROR_FAILED)); |
| } |
| |
| void FileSystemOperationImpl::CreateDirectory(const FileSystemURL& url, |
| bool exclusive, |
| bool recursive, |
| StatusCallback callback) { |
| CheckOperationType(OperationType::kCreateDirectory); |
| |
| auto split_callback = base::SplitOnceCallback(std::move(callback)); |
| GetBucketSpaceRemainingAndRunTask( |
| url, |
| base::BindOnce(&FileSystemOperationImpl::DoCreateDirectory, |
| weak_factory_.GetWeakPtr(), url, |
| std::move(split_callback.first), exclusive, recursive), |
| base::BindOnce(std::move(split_callback.second), |
| base::File::FILE_ERROR_FAILED)); |
| } |
| |
| void FileSystemOperationImpl::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) { |
| DCHECK(copy_or_move_hook_delegate); |
| CheckOperationType(OperationType::kCopy); |
| DCHECK(!recursive_operation_delegate_); |
| |
| recursive_operation_delegate_ = std::make_unique<CopyOrMoveOperationDelegate>( |
| file_system_context(), src_url, dest_url, |
| CopyOrMoveOperationDelegate::OPERATION_COPY, options, error_behavior, |
| std::move(copy_or_move_hook_delegate), |
| base::BindOnce(&FileSystemOperationImpl::DidFinishOperation, |
| weak_factory_.GetWeakPtr(), std::move(callback))); |
| recursive_operation_delegate_->RunRecursively(); |
| } |
| |
| void FileSystemOperationImpl::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) { |
| DCHECK(copy_or_move_hook_delegate); |
| CheckOperationType(OperationType::kMove); |
| DCHECK(!recursive_operation_delegate_); |
| recursive_operation_delegate_ = std::make_unique<CopyOrMoveOperationDelegate>( |
| file_system_context(), src_url, dest_url, |
| CopyOrMoveOperationDelegate::OPERATION_MOVE, options, error_behavior, |
| std::move(copy_or_move_hook_delegate), |
| base::BindOnce(&FileSystemOperationImpl::DidFinishOperation, |
| weak_factory_.GetWeakPtr(), std::move(callback))); |
| recursive_operation_delegate_->RunRecursively(); |
| } |
| |
| void FileSystemOperationImpl::DirectoryExists(const FileSystemURL& url, |
| StatusCallback callback) { |
| CheckOperationType(OperationType::kDirectoryExists); |
| async_file_util_->GetFileInfo( |
| std::move(operation_context_), url, {GetMetadataField::kIsDirectory}, |
| base::BindOnce(&FileSystemOperationImpl::DidDirectoryExists, |
| weak_factory_.GetWeakPtr(), std::move(callback))); |
| } |
| |
| void FileSystemOperationImpl::FileExists(const FileSystemURL& url, |
| StatusCallback callback) { |
| CheckOperationType(OperationType::kFileExists); |
| async_file_util_->GetFileInfo( |
| std::move(operation_context_), url, {GetMetadataField::kIsDirectory}, |
| base::BindOnce(&FileSystemOperationImpl::DidFileExists, |
| weak_factory_.GetWeakPtr(), std::move(callback))); |
| } |
| |
| void FileSystemOperationImpl::GetMetadata(const FileSystemURL& url, |
| GetMetadataFieldSet fields, |
| GetMetadataCallback callback) { |
| CheckOperationType(OperationType::kGetMetadata); |
| async_file_util_->GetFileInfo(std::move(operation_context_), url, fields, |
| std::move(callback)); |
| } |
| |
| void FileSystemOperationImpl::ReadDirectory( |
| const FileSystemURL& url, |
| const ReadDirectoryCallback& callback) { |
| CheckOperationType(OperationType::kReadDirectory); |
| async_file_util_->ReadDirectory(std::move(operation_context_), url, callback); |
| } |
| |
| void FileSystemOperationImpl::Remove(const FileSystemURL& url, |
| bool recursive, |
| StatusCallback callback) { |
| CheckOperationType(OperationType::kRemove); |
| DCHECK(!recursive_operation_delegate_); |
| |
| if (recursive) { |
| // For recursive removal, try to delegate the operation to AsyncFileUtil |
| // first. If not supported, it is delegated to RemoveOperationDelegate |
| // in DidDeleteRecursively. |
| async_file_util_->DeleteRecursively( |
| std::move(operation_context_), url, |
| base::BindOnce(&FileSystemOperationImpl::DidDeleteRecursively, |
| weak_factory_.GetWeakPtr(), url, std::move(callback))); |
| return; |
| } |
| |
| recursive_operation_delegate_ = std::make_unique<RemoveOperationDelegate>( |
| file_system_context(), url, |
| base::BindOnce(&FileSystemOperationImpl::DidFinishOperation, |
| weak_factory_.GetWeakPtr(), std::move(callback))); |
| recursive_operation_delegate_->Run(); |
| } |
| |
| void FileSystemOperationImpl::WriteBlob( |
| const FileSystemURL& url, |
| std::unique_ptr<FileWriterDelegate> writer_delegate, |
| std::unique_ptr<BlobReader> blob_reader, |
| const WriteCallback& callback) { |
| CheckOperationType(OperationType::kWrite); |
| file_writer_delegate_ = std::move(writer_delegate); |
| file_writer_delegate_->Start( |
| std::move(blob_reader), |
| base::BindRepeating(&FileSystemOperationImpl::DidWrite, |
| weak_factory_.GetWeakPtr(), url, callback)); |
| } |
| |
| void FileSystemOperationImpl::Write( |
| const FileSystemURL& url, |
| std::unique_ptr<FileWriterDelegate> writer_delegate, |
| mojo::ScopedDataPipeConsumerHandle data_pipe, |
| const WriteCallback& callback) { |
| CheckOperationType(OperationType::kWrite); |
| file_writer_delegate_ = std::move(writer_delegate); |
| file_writer_delegate_->Start( |
| std::move(data_pipe), |
| base::BindRepeating(&FileSystemOperationImpl::DidWrite, |
| weak_factory_.GetWeakPtr(), url, callback)); |
| } |
| |
| void FileSystemOperationImpl::Truncate(const FileSystemURL& url, |
| int64_t length, |
| StatusCallback callback) { |
| CheckOperationType(OperationType::kTruncate); |
| |
| auto split_callback = base::SplitOnceCallback(std::move(callback)); |
| GetBucketSpaceRemainingAndRunTask( |
| url, |
| base::BindOnce(&FileSystemOperationImpl::DoTruncate, |
| weak_factory_.GetWeakPtr(), url, |
| std::move(split_callback.first), length), |
| base::BindOnce(std::move(split_callback.second), |
| base::File::FILE_ERROR_FAILED)); |
| } |
| |
| void FileSystemOperationImpl::TouchFile(const FileSystemURL& url, |
| const base::Time& last_access_time, |
| const base::Time& last_modified_time, |
| StatusCallback callback) { |
| CheckOperationType(OperationType::kTouchFile); |
| |
| async_file_util_->Touch( |
| std::move(operation_context_), url, last_access_time, last_modified_time, |
| base::BindOnce(&FileSystemOperationImpl::DidFinishOperation, |
| weak_factory_.GetWeakPtr(), std::move(callback))); |
| } |
| |
| void FileSystemOperationImpl::OpenFile(const FileSystemURL& url, |
| uint32_t file_flags, |
| OpenFileCallback callback) { |
| CheckOperationType(OperationType::kOpenFile); |
| |
| if (file_flags & |
| (base::File::FLAG_WIN_TEMPORARY | base::File::FLAG_WIN_HIDDEN)) { |
| std::move(callback).Run(base::File(base::File::FILE_ERROR_FAILED), |
| base::OnceClosure()); |
| return; |
| } |
| |
| auto split_callback = base::SplitOnceCallback(std::move(callback)); |
| GetBucketSpaceRemainingAndRunTask( |
| url, |
| base::BindOnce(&FileSystemOperationImpl::DoOpenFile, |
| weak_factory_.GetWeakPtr(), url, |
| std::move(split_callback.first), file_flags), |
| base::BindOnce(std::move(split_callback.second), |
| base::File(base::File::FILE_ERROR_FAILED), |
| base::OnceClosure())); |
| } |
| |
| // We can only get here on a write or truncate that's not yet completed. |
| // We don't support cancelling any other operation at this time. |
| void FileSystemOperationImpl::Cancel(StatusCallback cancel_callback) { |
| DCHECK(cancel_callback_.is_null()); |
| cancel_callback_ = std::move(cancel_callback); |
| |
| if (file_writer_delegate_.get()) { |
| CHECK_EQ(OperationType::kWrite, type_); |
| // This will call DidWrite() with ABORT status code. |
| file_writer_delegate_->Cancel(); |
| } else if (recursive_operation_delegate_) { |
| // This will call DidFinishOperation() with ABORT status code. |
| recursive_operation_delegate_->Cancel(); |
| } else { |
| // For truncate we have no way to cancel the inflight operation (for now). |
| // Let it just run and dispatch cancel callback later. |
| CHECK_EQ(OperationType::kTruncate, type_); |
| } |
| } |
| |
| void FileSystemOperationImpl::CreateSnapshotFile( |
| const FileSystemURL& url, |
| SnapshotFileCallback callback) { |
| CheckOperationType(OperationType::kCreateSnapshotFile); |
| async_file_util_->CreateSnapshotFile(std::move(operation_context_), url, |
| std::move(callback)); |
| } |
| |
| void FileSystemOperationImpl::CopyInForeignFile( |
| const base::FilePath& src_local_disk_file_path, |
| const FileSystemURL& dest_url, |
| StatusCallback callback) { |
| CheckOperationType(OperationType::kCopyInForeignFile); |
| |
| auto split_callback = base::SplitOnceCallback(std::move(callback)); |
| GetBucketSpaceRemainingAndRunTask( |
| dest_url, |
| base::BindOnce(&FileSystemOperationImpl::DoCopyInForeignFile, |
| weak_factory_.GetWeakPtr(), src_local_disk_file_path, |
| dest_url, std::move(split_callback.first)), |
| base::BindOnce(std::move(split_callback.second), |
| base::File::FILE_ERROR_FAILED)); |
| } |
| |
| void FileSystemOperationImpl::RemoveFile(const FileSystemURL& url, |
| StatusCallback callback) { |
| CheckOperationType(OperationType::kRemove); |
| async_file_util_->DeleteFile( |
| std::move(operation_context_), url, |
| base::BindOnce(&FileSystemOperationImpl::DidFinishOperation, |
| weak_factory_.GetWeakPtr(), std::move(callback))); |
| } |
| |
| void FileSystemOperationImpl::RemoveDirectory(const FileSystemURL& url, |
| StatusCallback callback) { |
| CheckOperationType(OperationType::kRemove); |
| async_file_util_->DeleteDirectory( |
| std::move(operation_context_), url, |
| base::BindOnce(&FileSystemOperationImpl::DidFinishOperation, |
| weak_factory_.GetWeakPtr(), std::move(callback))); |
| } |
| |
| void FileSystemOperationImpl::CopyFileLocal( |
| const FileSystemURL& src_url, |
| const FileSystemURL& dest_url, |
| CopyOrMoveOptionSet options, |
| const CopyFileProgressCallback& progress_callback, |
| StatusCallback callback) { |
| CheckOperationType(OperationType::kCopy); |
| // Don't just DCHECK src_url.IsInSameFileSystem(dest_url). We don't care if |
| // the two URLs are mounted in two different isolated file systems. As long |
| // as their origin and type are the same, they are part of the same file |
| // system, and local operations are allowed. See https://crbug.com/1396116. |
| DCHECK(src_url.origin() == dest_url.origin() || |
| (src_url.origin().opaque() && dest_url.origin().opaque())); |
| DCHECK_EQ(src_url.type(), dest_url.type()); |
| |
| auto split_callback = base::SplitOnceCallback(std::move(callback)); |
| GetBucketSpaceRemainingAndRunTask( |
| dest_url, |
| base::BindOnce(&FileSystemOperationImpl::DoCopyFileLocal, |
| weak_factory_.GetWeakPtr(), src_url, dest_url, options, |
| progress_callback, std::move(split_callback.first)), |
| base::BindOnce(std::move(split_callback.second), |
| base::File::FILE_ERROR_FAILED)); |
| } |
| |
| void FileSystemOperationImpl::MoveFileLocal(const FileSystemURL& src_url, |
| const FileSystemURL& dest_url, |
| CopyOrMoveOptionSet options, |
| StatusCallback callback) { |
| CheckOperationType(OperationType::kMove); |
| // Don't just DCHECK src_url.IsInSameFileSystem(dest_url). We don't care if |
| // the two URLs are mounted in two different isolated file systems. As long |
| // as their origin and type are the same, they are part of the same file |
| // system, and local operations are allowed. See https://crbug.com/1396116. |
| DCHECK(src_url.origin() == dest_url.origin() || |
| (src_url.origin().opaque() && dest_url.origin().opaque())); |
| DCHECK_EQ(src_url.type(), dest_url.type()); |
| |
| auto split_callback = base::SplitOnceCallback(std::move(callback)); |
| GetBucketSpaceRemainingAndRunTask( |
| dest_url, |
| base::BindOnce(&FileSystemOperationImpl::DoMoveFileLocal, |
| weak_factory_.GetWeakPtr(), src_url, dest_url, options, |
| std::move(split_callback.first)), |
| base::BindOnce(std::move(split_callback.second), |
| base::File::FILE_ERROR_FAILED)); |
| } |
| |
| base::File::Error FileSystemOperationImpl::SyncGetPlatformPath( |
| const FileSystemURL& url, |
| base::FilePath* platform_path) { |
| CheckOperationType(OperationType::kGetLocalPath); |
| if (!file_system_context()->IsSandboxFileSystem(url.type())) |
| return base::File::FILE_ERROR_INVALID_OPERATION; |
| FileSystemFileUtil* file_util = |
| file_system_context()->sandbox_delegate()->sync_file_util(); |
| file_util->GetLocalFilePath(operation_context_.get(), url, platform_path); |
| return base::File::FILE_OK; |
| } |
| |
| FileSystemOperationImpl::FileSystemOperationImpl( |
| OperationType type, |
| const FileSystemURL& url, |
| FileSystemContext* file_system_context, |
| std::unique_ptr<FileSystemOperationContext> operation_context, |
| base::PassKey<FileSystemOperation>) |
| : type_(type), |
| file_system_context_(file_system_context), |
| operation_context_(std::move(operation_context)), |
| async_file_util_(nullptr) { |
| weak_ptr_ = weak_factory_.GetWeakPtr(); |
| |
| DCHECK(operation_context_.get()); |
| async_file_util_ = file_system_context_->GetAsyncFileUtil(url.type()); |
| DCHECK(async_file_util_); |
| } |
| |
| void FileSystemOperationImpl::GetBucketSpaceRemainingAndRunTask( |
| const FileSystemURL& url, |
| base::OnceClosure task, |
| base::OnceClosure error_callback) { |
| const scoped_refptr<QuotaManagerProxy>& quota_manager_proxy = |
| file_system_context()->quota_manager_proxy(); |
| if (!quota_manager_proxy || |
| !file_system_context()->GetQuotaUtil(url.type())) { |
| // If we don't have the quota manager or the requested filesystem type |
| // does not support quota, we should be able to let it go. |
| operation_context_->set_allowed_bytes_growth( |
| std::numeric_limits<int64_t>::max()); |
| std::move(task).Run(); |
| return; |
| } |
| |
| BucketLocator bucket = |
| url.bucket().value_or(BucketLocator::ForDefaultBucket(url.storage_key())); |
| |
| DCHECK(quota_manager_proxy); |
| quota_manager_proxy->GetBucketSpaceRemaining( |
| bucket, base::SequencedTaskRunner::GetCurrentDefault(), |
| base::BindOnce(&FileSystemOperationImpl::DidGetBucketSpaceRemaining, |
| weak_ptr_, std::move(task), std::move(error_callback))); |
| } |
| |
| void FileSystemOperationImpl::DidGetBucketSpaceRemaining( |
| base::OnceClosure task, |
| base::OnceClosure error_callback, |
| QuotaErrorOr<int64_t> space_left) { |
| if (!space_left.has_value()) { |
| LOG(WARNING) << "Got unexpected quota error"; |
| std::move(error_callback).Run(); |
| return; |
| } |
| |
| operation_context_->set_allowed_bytes_growth(space_left.value()); |
| std::move(task).Run(); |
| } |
| |
| void FileSystemOperationImpl::DoCreateFile(const FileSystemURL& url, |
| StatusCallback callback, |
| bool exclusive) { |
| async_file_util_->EnsureFileExists( |
| std::move(operation_context_), url, |
| base::BindOnce( |
| exclusive ? &FileSystemOperationImpl::DidEnsureFileExistsExclusive |
| : &FileSystemOperationImpl::DidEnsureFileExistsNonExclusive, |
| weak_ptr_, std::move(callback))); |
| } |
| |
| void FileSystemOperationImpl::DoCreateDirectory(const FileSystemURL& url, |
| StatusCallback callback, |
| bool exclusive, |
| bool recursive) { |
| async_file_util_->CreateDirectory( |
| std::move(operation_context_), url, exclusive, recursive, |
| base::BindOnce(&FileSystemOperationImpl::DidFinishOperation, weak_ptr_, |
| std::move(callback))); |
| } |
| |
| void FileSystemOperationImpl::DoCopyFileLocal( |
| const FileSystemURL& src_url, |
| const FileSystemURL& dest_url, |
| CopyOrMoveOptionSet options, |
| const CopyFileProgressCallback& progress_callback, |
| StatusCallback callback) { |
| async_file_util_->CopyFileLocal( |
| std::move(operation_context_), src_url, dest_url, options, |
| progress_callback, |
| base::BindOnce(&FileSystemOperationImpl::DidFinishOperation, weak_ptr_, |
| std::move(callback))); |
| } |
| |
| void FileSystemOperationImpl::DoMoveFileLocal(const FileSystemURL& src_url, |
| const FileSystemURL& dest_url, |
| CopyOrMoveOptionSet options, |
| StatusCallback callback) { |
| async_file_util_->MoveFileLocal( |
| std::move(operation_context_), src_url, dest_url, options, |
| base::BindOnce(&FileSystemOperationImpl::DidFinishOperation, weak_ptr_, |
| std::move(callback))); |
| } |
| |
| void FileSystemOperationImpl::DoCopyInForeignFile( |
| const base::FilePath& src_local_disk_file_path, |
| const FileSystemURL& dest_url, |
| StatusCallback callback) { |
| async_file_util_->CopyInForeignFile( |
| std::move(operation_context_), src_local_disk_file_path, dest_url, |
| base::BindOnce(&FileSystemOperationImpl::DidFinishOperation, weak_ptr_, |
| std::move(callback))); |
| } |
| |
| void FileSystemOperationImpl::DoTruncate(const FileSystemURL& url, |
| StatusCallback callback, |
| int64_t length) { |
| async_file_util_->Truncate( |
| std::move(operation_context_), url, length, |
| base::BindOnce(&FileSystemOperationImpl::DidFinishOperation, weak_ptr_, |
| std::move(callback))); |
| } |
| |
| void FileSystemOperationImpl::DoOpenFile(const FileSystemURL& url, |
| OpenFileCallback callback, |
| uint32_t file_flags) { |
| async_file_util_->CreateOrOpen( |
| std::move(operation_context_), url, file_flags, |
| base::BindOnce(&DidOpenFile, file_system_context_, weak_ptr_, |
| std::move(callback))); |
| } |
| |
| void FileSystemOperationImpl::DidEnsureFileExistsExclusive( |
| StatusCallback callback, |
| base::File::Error rv, |
| bool created) { |
| if (rv == base::File::FILE_OK && !created) { |
| std::move(callback).Run(base::File::FILE_ERROR_EXISTS); |
| } else { |
| DidFinishOperation(std::move(callback), rv); |
| } |
| } |
| |
| void FileSystemOperationImpl::DidEnsureFileExistsNonExclusive( |
| StatusCallback callback, |
| base::File::Error rv, |
| bool /* created */) { |
| DidFinishOperation(std::move(callback), rv); |
| } |
| |
| void FileSystemOperationImpl::DidFinishOperation(StatusCallback callback, |
| base::File::Error rv) { |
| if (!cancel_callback_.is_null()) { |
| StatusCallback cancel_callback = std::move(cancel_callback_); |
| std::move(callback).Run(rv); |
| |
| // Return OK only if we succeeded to stop the operation. |
| std::move(cancel_callback) |
| .Run(rv == base::File::FILE_ERROR_ABORT |
| ? base::File::FILE_OK |
| : base::File::FILE_ERROR_INVALID_OPERATION); |
| } else { |
| std::move(callback).Run(rv); |
| } |
| } |
| |
| void FileSystemOperationImpl::DidDirectoryExists( |
| StatusCallback callback, |
| base::File::Error rv, |
| const base::File::Info& file_info) { |
| if (rv == base::File::FILE_OK && !file_info.is_directory) |
| rv = base::File::FILE_ERROR_NOT_A_DIRECTORY; |
| std::move(callback).Run(rv); |
| } |
| |
| void FileSystemOperationImpl::DidFileExists(StatusCallback callback, |
| base::File::Error rv, |
| const base::File::Info& file_info) { |
| if (rv == base::File::FILE_OK && file_info.is_directory) |
| rv = base::File::FILE_ERROR_NOT_A_FILE; |
| std::move(callback).Run(rv); |
| } |
| |
| void FileSystemOperationImpl::DidDeleteRecursively(const FileSystemURL& url, |
| StatusCallback callback, |
| base::File::Error rv) { |
| if (rv == base::File::FILE_ERROR_INVALID_OPERATION) { |
| // Recursive removal is not supported on this platform. |
| DCHECK(!recursive_operation_delegate_); |
| recursive_operation_delegate_ = std::make_unique<RemoveOperationDelegate>( |
| file_system_context(), url, |
| base::BindOnce(&FileSystemOperationImpl::DidFinishOperation, weak_ptr_, |
| std::move(callback))); |
| recursive_operation_delegate_->RunRecursively(); |
| return; |
| } |
| |
| std::move(callback).Run(rv); |
| } |
| |
| void FileSystemOperationImpl::DidWrite( |
| const FileSystemURL& url, |
| const WriteCallback& write_callback, |
| base::File::Error rv, |
| int64_t bytes, |
| FileWriterDelegate::WriteProgressStatus write_status) { |
| const bool complete = |
| (write_status != FileWriterDelegate::SUCCESS_IO_PENDING); |
| if (complete && write_status != FileWriterDelegate::ERROR_WRITE_NOT_STARTED) { |
| DCHECK(operation_context_); |
| operation_context_->change_observers()->Notify( |
| &FileChangeObserver::OnModifyFile, url); |
| } |
| |
| StatusCallback cancel_callback = std::move(cancel_callback_); |
| write_callback.Run(rv, bytes, complete); |
| if (!cancel_callback.is_null()) |
| std::move(cancel_callback).Run(base::File::FILE_OK); |
| } |
| |
| void FileSystemOperationImpl::CheckOperationType(OperationType type) { |
| CHECK_EQ(type, type_); |
| CHECK(!operation_called_); |
| operation_called_ = true; |
| } |
| |
| } // namespace storage |