blob: 9ad62cf4722c7e9619299281a373b53658386df2 [file] [log] [blame]
// Copyright 2018 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.
#include "storage/browser/fileapi/file_writer_impl.h"
#include "base/bind.h"
#include "base/callback_helpers.h"
#include "mojo/public/cpp/system/data_pipe_drainer.h"
#include "storage/browser/blob/blob_data_handle.h"
#include "storage/browser/blob/blob_storage_context.h"
namespace storage {
FileWriterImpl::FileWriterImpl(
FileSystemURL url,
std::unique_ptr<FileSystemOperationRunner> operation_runner,
base::WeakPtr<BlobStorageContext> blob_context)
: operation_runner_(std::move(operation_runner)),
blob_context_(std::move(blob_context)),
url_(std::move(url)),
weak_ptr_factory_(this) {
DCHECK(url_.is_valid());
}
FileWriterImpl::~FileWriterImpl() = default;
void FileWriterImpl::Write(uint64_t position,
blink::mojom::BlobPtr blob,
WriteCallback callback) {
blob_context_->GetBlobDataFromBlobPtr(
std::move(blob),
base::BindOnce(&FileWriterImpl::DoWrite, weak_ptr_factory_.GetWeakPtr(),
std::move(callback), position));
}
void FileWriterImpl::WriteStream(uint64_t position,
mojo::ScopedDataPipeConsumerHandle stream,
WriteStreamCallback callback) {
// FileSystemOperationRunner assumes that positions passed to Write are always
// valid, and will NOTREACHED() if that is not the case, so first check the
// size of the file to make sure the position passed in from the renderer is
// in fact valid.
// Of course the file could still change between checking its size and the
// write operation being started, but this is at least a lot better than the
// old implementation where the renderer only checks against how big it thinks
// the file currently is.
operation_runner_->GetMetadata(
url_, FileSystemOperation::GET_METADATA_FIELD_SIZE,
base::BindRepeating(&FileWriterImpl::DoWriteStreamWithFileInfo,
base::Unretained(this),
base::AdaptCallbackForRepeating(std::move(callback)),
position, base::Passed(std::move(stream))));
}
void FileWriterImpl::Truncate(uint64_t length, TruncateCallback callback) {
operation_runner_->Truncate(
url_, length,
base::BindRepeating(
&FileWriterImpl::DidTruncate, base::Unretained(this),
base::AdaptCallbackForRepeating(std::move(callback))));
}
void FileWriterImpl::DoWrite(WriteCallback callback,
uint64_t position,
std::unique_ptr<BlobDataHandle> blob) {
if (!blob) {
std::move(callback).Run(base::File::FILE_ERROR_FAILED, 0);
return;
}
// FileSystemOperationRunner assumes that positions passed to Write are always
// valid, and will NOTREACHED() if that is not the case, so first check the
// size of the file to make sure the position passed in from the renderer is
// in fact valid.
// Of course the file could still change between checking its size and the
// write operation being started, but this is at least a lot better than the
// old implementation where the renderer only checks against how big it thinks
// the file currently is.
operation_runner_->GetMetadata(
url_, FileSystemOperation::GET_METADATA_FIELD_SIZE,
base::BindRepeating(&FileWriterImpl::DoWriteWithFileInfo,
base::Unretained(this),
base::AdaptCallbackForRepeating(std::move(callback)),
position, base::Passed(std::move(blob))));
}
void FileWriterImpl::DoWriteWithFileInfo(WriteCallback callback,
uint64_t position,
std::unique_ptr<BlobDataHandle> blob,
base::File::Error result,
const base::File::Info& file_info) {
if (file_info.size < 0 || position > static_cast<uint64_t>(file_info.size)) {
std::move(callback).Run(base::File::FILE_ERROR_FAILED, 0);
return;
}
operation_runner_->Write(
url_, std::move(blob), position,
base::BindRepeating(&FileWriterImpl::DidWrite, base::Unretained(this),
base::AdaptCallbackForRepeating(std::move(callback)),
base::Owned(new WriteState())));
}
void FileWriterImpl::DoWriteStreamWithFileInfo(
WriteStreamCallback callback,
uint64_t position,
mojo::ScopedDataPipeConsumerHandle data_pipe,
base::File::Error result,
const base::File::Info& file_info) {
if (file_info.size < 0 || position > static_cast<uint64_t>(file_info.size)) {
std::move(callback).Run(base::File::FILE_ERROR_FAILED, 0);
return;
}
operation_runner_->Write(
url_, std::move(data_pipe), position,
base::BindRepeating(&FileWriterImpl::DidWrite, base::Unretained(this),
base::AdaptCallbackForRepeating(std::move(callback)),
base::Owned(new WriteState())));
}
void FileWriterImpl::DidWrite(WriteCallback callback,
WriteState* state,
base::File::Error result,
int64_t bytes,
bool complete) {
DCHECK(state);
state->bytes_written += bytes;
if (complete)
std::move(callback).Run(result, state->bytes_written);
}
void FileWriterImpl::DidTruncate(TruncateCallback callback,
base::File::Error result) {
std::move(callback).Run(result);
}
} // namespace storage