blob: fd9ab532c4c776900dfa7868c9b6c87b682ae94f [file] [log] [blame]
// Copyright (c) 2012 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 "webkit/chromeos/fileapi/remote_file_stream_writer.h"
#include "net/base/io_buffer.h"
#include "net/base/net_errors.h"
#include "webkit/blob/local_file_stream_reader.h"
#include "webkit/blob/shareable_file_reference.h"
#include "webkit/chromeos/fileapi/remote_file_system_proxy.h"
#include "webkit/fileapi/local_file_stream_writer.h"
namespace fileapi {
RemoteFileStreamWriter::RemoteFileStreamWriter(
const scoped_refptr<RemoteFileSystemProxyInterface>& remote_filesystem,
const FileSystemURL& url,
int64 offset)
: remote_filesystem_(remote_filesystem),
url_(url),
initial_offset_(offset),
has_pending_create_snapshot_(false),
weak_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) {
}
RemoteFileStreamWriter::~RemoteFileStreamWriter() {
}
int RemoteFileStreamWriter::Write(net::IOBuffer* buf,
int buf_len,
const net::CompletionCallback& callback) {
DCHECK(!has_pending_create_snapshot_);
DCHECK(pending_cancel_callback_.is_null());
if (!local_file_writer_.get()) {
has_pending_create_snapshot_ = true;
// In this RemoteFileStreamWriter, we only create snapshot file and don't
// have explicit close operation. This is ok, because close is automatically
// triggered by a refcounted |file_ref_| passed to OnFileOpened, from the
// destructor of RemoteFileStreamWriter.
remote_filesystem_->CreateWritableSnapshotFile(
url_,
base::Bind(&RemoteFileStreamWriter::OnFileOpened,
weak_factory_.GetWeakPtr(),
make_scoped_refptr(buf),
buf_len,
callback));
return net::ERR_IO_PENDING;
}
return local_file_writer_->Write(buf, buf_len, callback);
}
void RemoteFileStreamWriter::OnFileOpened(
net::IOBuffer* buf,
int buf_len,
const net::CompletionCallback& callback,
base::PlatformFileError open_result,
const FilePath& local_path,
const scoped_refptr<webkit_blob::ShareableFileReference>& file_ref) {
has_pending_create_snapshot_ = false;
if (!pending_cancel_callback_.is_null()) {
InvokePendingCancelCallback(net::OK);
return;
}
if (open_result != base::PLATFORM_FILE_OK) {
callback.Run(net::PlatformFileErrorToNetError(open_result));
return;
}
// Hold the reference to the file. Releasing the reference notifies the file
// system about to close file.
file_ref_ = file_ref;
DCHECK(!local_file_writer_.get());
local_file_writer_.reset(new fileapi::LocalFileStreamWriter(local_path,
initial_offset_));
int result = local_file_writer_->Write(buf, buf_len, callback);
if (result != net::ERR_IO_PENDING)
callback.Run(result);
}
int RemoteFileStreamWriter::Cancel(const net::CompletionCallback& callback) {
DCHECK(!callback.is_null());
DCHECK(pending_cancel_callback_.is_null());
// If file open operation is in-flight, wait for its completion and cancel
// further write operation in OnFileOpened.
if (has_pending_create_snapshot_) {
pending_cancel_callback_ = callback;
return net::ERR_IO_PENDING;
}
// If LocalFileWriter is already created, just delegate the cancel to it.
if (local_file_writer_.get()) {
pending_cancel_callback_ = callback;
return local_file_writer_->Cancel(
base::Bind(&RemoteFileStreamWriter::InvokePendingCancelCallback,
weak_factory_.GetWeakPtr()));
}
// Write() is not called yet.
return net::ERR_UNEXPECTED;
}
void RemoteFileStreamWriter::InvokePendingCancelCallback(int result) {
net::CompletionCallback callback = pending_cancel_callback_;
pending_cancel_callback_.Reset();
callback.Run(result);
}
} // namespace gdata