#include "content/browser/file_system_access/file_system_access_file_handle_impl.h"
#include "base/files/file_error_or.h"
#include "base/files/file_util.h"
#include "base/files/safe_base_name.h"
#include "base/functional/callback_forward.h"
#include "base/functional/callback_helpers.h"
#include "base/logging.h"
#include "base/strings/stringprintf.h"
#include "base/task/task_traits.h"
#include "base/task/thread_pool.h"
#include "base/uuid.h"
#include "build/build_config.h"
#include "components/file_access/scoped_file_access_delegate.h"
#include "content/browser/file_system_access/features.h"
#include "content/browser/file_system_access/file_system_access_access_handle_host_impl.h"
#include "content/browser/file_system_access/file_system_access_error.h"
#include "content/browser/file_system_access/file_system_access_handle_base.h"
#include "content/browser/file_system_access/file_system_access_lock_manager.h"
#include "content/browser/file_system_access/file_system_access_manager_impl.h"
#include "content/browser/file_system_access/file_system_access_transfer_token_impl.h"
#include "content/public/browser/browser_task_traits.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/render_frame_host.h"
#include "mojo/public/cpp/bindings/pending_receiver.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "net/base/mime_util.h"
#include "storage/browser/blob/blob_data_builder.h"
#include "storage/browser/blob/blob_impl.h"
#include "storage/browser/blob/blob_storage_context.h"
#include "storage/browser/file_system/copy_or_move_hook_delegate.h"
#include "storage/browser/file_system/file_system_operation_runner.h"
#include "storage/common/file_system/file_system_types.h"
#include "third_party/blink/public/mojom/blob/blob.mojom.h"
#include "third_party/blink/public/mojom/blob/serialized_blob.mojom.h"
#include "third_party/blink/public/mojom/file_system_access/file_system_access_cloud_identifier.mojom.h"
#include "third_party/blink/public/mojom/file_system_access/file_system_access_error.mojom.h"
#include "third_party/blink/public/mojom/file_system_access/file_system_access_file_handle.mojom.h"
#include "third_party/blink/public/mojom/file_system_access/file_system_access_file_modification_host.mojom.h"
#include "third_party/blink/public/mojom/file_system_access/file_system_access_transfer_token.mojom.h"
#if BUILDFLAG(IS_ANDROID)
#include "base/path_service.h"
#include "base/strings/escape.h"
#include "content/public/common/content_paths.h"
#endif
#if BUILDFLAG(IS_WIN)
#include <windows.h>
#endif
#if BUILDFLAG(IS_MAC)
#include <sys/clonefile.h>
#include "base/files/file.h"
#endif
FileSystemAccessStatus;
BlobDataHandle;
BlobImpl;
FileSystemOperation;
FileSystemOperationRunner;
namespace content {
namespace {
std::pair<base::File, base::FileErrorOr<int64_t>> GetFileLengthOnBlockingThread(
base::File file) { … }
#if BUILDFLAG(IS_ANDROID)
void EnsureSwapDirExists(base::FilePath swap_dir) {
if (!base::PathExists(swap_dir)) {
if (!base::CreateDirectory(swap_dir)) {
DLOG(ERROR) << "Error creating swap dir " << swap_dir;
}
}
}
#endif
bool HasWritePermission(const base::FilePath& path) { … }
#if BUILDFLAG(IS_MAC)
base::File::Error CreateCowSwapFile(const storage::FileSystemURL& source_url,
const storage::FileSystemURL& swap_url) {
return clonefile(source_url.path().value().c_str(),
swap_url.path().value().c_str(),
0) == 0
? base::File::Error::FILE_OK
: base::File::GetLastFileError();
}
#endif
file_access::ScopedFileAccessDelegate::RequestFilesAccessIOCallback
CreateFileAccessCallback(const GURL& destination) { … }
}
FileSystemAccessFileHandleImpl::FileSystemAccessFileHandleImpl(
FileSystemAccessManagerImpl* manager,
const BindingContext& context,
const storage::FileSystemURL& url,
const SharedHandleState& handle_state)
: … { … }
FileSystemAccessFileHandleImpl::~FileSystemAccessFileHandleImpl() = default;
void FileSystemAccessFileHandleImpl::GetPermissionStatus(
bool writable,
GetPermissionStatusCallback callback) { … }
void FileSystemAccessFileHandleImpl::RequestPermission(
bool writable,
RequestPermissionCallback callback) { … }
void FileSystemAccessFileHandleImpl::AsBlob(AsBlobCallback callback) { … }
void FileSystemAccessFileHandleImpl::CreateFileWriter(
bool keep_existing_data,
bool auto_close,
blink::mojom::FileSystemAccessWritableFileStreamLockMode mode,
CreateFileWriterCallback callback) { … }
void FileSystemAccessFileHandleImpl::Move(
mojo::PendingRemote<blink::mojom::FileSystemAccessTransferToken>
destination_directory,
const std::string& new_entry_name,
MoveCallback callback) { … }
void FileSystemAccessFileHandleImpl::Rename(const std::string& new_entry_name,
RenameCallback callback) { … }
void FileSystemAccessFileHandleImpl::Remove(RemoveCallback callback) { … }
void FileSystemAccessFileHandleImpl::OpenAccessHandle(
blink::mojom::FileSystemAccessAccessHandleLockMode mode,
OpenAccessHandleCallback callback) { … }
void FileSystemAccessFileHandleImpl::DidTakeAccessHandleLock(
OpenAccessHandleCallback callback,
scoped_refptr<FileSystemAccessLockManager::LockHandle> lock) { … }
void FileSystemAccessFileHandleImpl::DoOpenIncognitoFile(
scoped_refptr<FileSystemAccessLockManager::LockHandle> lock,
OpenAccessHandleCallback callback) { … }
void FileSystemAccessFileHandleImpl::DoOpenFile(
scoped_refptr<FileSystemAccessLockManager::LockHandle> lock,
OpenAccessHandleCallback callback) { … }
void FileSystemAccessFileHandleImpl::DoGetLengthAfterOpenFile(
OpenAccessHandleCallback callback,
scoped_refptr<FileSystemAccessLockManager::LockHandle> lock,
base::File file,
base::ScopedClosureRunner on_close_callback) { … }
void FileSystemAccessFileHandleImpl::DidOpenFileAndGetLength(
OpenAccessHandleCallback callback,
scoped_refptr<FileSystemAccessLockManager::LockHandle> lock,
base::ScopedClosureRunner on_close_callback,
std::pair<base::File, base::FileErrorOr<int64_t>> file_and_length) { … }
void FileSystemAccessFileHandleImpl::IsSameEntry(
mojo::PendingRemote<blink::mojom::FileSystemAccessTransferToken> token,
IsSameEntryCallback callback) { … }
void FileSystemAccessFileHandleImpl::IsSameEntryImpl(
IsSameEntryCallback callback,
FileSystemAccessTransferTokenImpl* other) { … }
void FileSystemAccessFileHandleImpl::Transfer(
mojo::PendingReceiver<blink::mojom::FileSystemAccessTransferToken> token) { … }
void FileSystemAccessFileHandleImpl::DidGetMetaDataForBlob(
AsBlobCallback callback,
base::File::Error result,
const base::File::Info& info) { … }
void FileSystemAccessFileHandleImpl::CreateFileWriterImpl(
bool keep_existing_data,
bool auto_close,
blink::mojom::FileSystemAccessWritableFileStreamLockMode mode,
CreateFileWriterCallback callback) { … }
void FileSystemAccessFileHandleImpl::DidVerifyHasWritePermissions(
bool keep_existing_data,
bool auto_close,
blink::mojom::FileSystemAccessWritableFileStreamLockMode mode,
CreateFileWriterCallback callback,
bool can_write) { … }
void FileSystemAccessFileHandleImpl::StartCreateSwapFile(
int start_count,
bool keep_existing_data,
bool auto_close,
CreateFileWriterCallback callback,
scoped_refptr<FileSystemAccessLockManager::LockHandle> lock) { … }
void FileSystemAccessFileHandleImpl::DidTakeSwapLock(
int count,
const storage::FileSystemURL& swap_url,
bool keep_existing_data,
bool auto_close,
scoped_refptr<FileSystemAccessLockManager::LockHandle> lock,
CreateFileWriterCallback callback,
scoped_refptr<FileSystemAccessLockManager::LockHandle> swap_lock) { … }
void FileSystemAccessFileHandleImpl::DidCheckSwapFileExists(
int count,
const storage::FileSystemURL& swap_url,
bool auto_close,
scoped_refptr<FileSystemAccessLockManager::LockHandle> lock,
scoped_refptr<FileSystemAccessLockManager::LockHandle> swap_lock,
CreateFileWriterCallback callback,
base::File::Error result) { … }
void FileSystemAccessFileHandleImpl::CreateSwapFileFromCopy(
int count,
const storage::FileSystemURL& swap_url,
bool auto_close,
scoped_refptr<FileSystemAccessLockManager::LockHandle> lock,
scoped_refptr<FileSystemAccessLockManager::LockHandle> swap_lock,
CreateFileWriterCallback callback) { … }
#if BUILDFLAG(IS_MAC)
void FileSystemAccessFileHandleImpl::CreateClonedSwapFile(
int count,
const storage::FileSystemURL& swap_url,
bool auto_close,
scoped_refptr<FileSystemAccessLockManager::LockHandle> lock,
scoped_refptr<FileSystemAccessLockManager::LockHandle> swap_lock,
CreateFileWriterCallback callback) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK(count >= 0);
DCHECK(max_swap_files_ >= 0);
DCHECK(CanUseCowSwapFile());
auto after_clone_callback = base::BindOnce(
&FileSystemAccessFileHandleImpl::DidCloneSwapFile,
weak_factory_.GetWeakPtr(), count, swap_url, auto_close, std::move(lock),
std::move(swap_lock), std::move(callback));
if (swap_file_cloning_will_fail_for_testing_) {
std::move(after_clone_callback).Run(base::File::Error::FILE_ERROR_ABORT);
return;
}
base::ThreadPool::PostTaskAndReplyWithResult(
FROM_HERE, {base::MayBlock()},
base::BindOnce(&CreateCowSwapFile, url(), swap_url),
std::move(after_clone_callback));
}
void FileSystemAccessFileHandleImpl::DidCloneSwapFile(
int count,
const storage::FileSystemURL& swap_url,
bool auto_close,
scoped_refptr<FileSystemAccessLockManager::LockHandle> lock,
scoped_refptr<FileSystemAccessLockManager::LockHandle> swap_lock,
CreateFileWriterCallback callback,
base::File::Error result) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK(CanUseCowSwapFile());
swap_file_clone_result_for_testing_ = result;
if (result == base::File::FILE_ERROR_EXISTS) {
StartCreateSwapFile(count + 1, true, auto_close,
std::move(callback), std::move(lock));
return;
}
if (result != base::File::FILE_OK) {
CreateSwapFileFromCopy(count, swap_url, auto_close, std::move(lock),
std::move(swap_lock), std::move(callback));
return;
}
std::move(callback).Run(
file_system_access_error::Ok(),
manager()->CreateFileWriter(
context(), url(), swap_url, std::move(lock), std::move(swap_lock),
FileSystemAccessManagerImpl::SharedHandleState(
handle_state().read_grant, handle_state().write_grant),
auto_close));
}
#endif
void FileSystemAccessFileHandleImpl::DidCreateSwapFile(
int count,
const storage::FileSystemURL& swap_url,
bool keep_existing_data,
bool auto_close,
scoped_refptr<FileSystemAccessLockManager::LockHandle> lock,
scoped_refptr<FileSystemAccessLockManager::LockHandle> swap_lock,
CreateFileWriterCallback callback,
base::File::Error result) { … }
void FileSystemAccessFileHandleImpl::GetUniqueId(GetUniqueIdCallback callback) { … }
#if BUILDFLAG(IS_MAC)
bool FileSystemAccessFileHandleImpl::CanUseCowSwapFile() const {
return url().type() == storage::kFileSystemTypeLocal;
}
#endif
void FileSystemAccessFileHandleImpl::GetCloudIdentifiers(
GetCloudIdentifiersCallback callback) { … }
base::WeakPtr<FileSystemAccessHandleBase>
FileSystemAccessFileHandleImpl::AsWeakPtr() { … }
}