Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(35)

Unified Diff: webkit/fileapi/sandbox_file_writer.cc

Issue 10387054: Implement SandboxFileWriter and rewrite FileWriterDelegate to use it (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: adding CancelIfRequested Created 8 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: webkit/fileapi/sandbox_file_writer.cc
diff --git a/webkit/fileapi/sandbox_file_writer.cc b/webkit/fileapi/sandbox_file_writer.cc
new file mode 100644
index 0000000000000000000000000000000000000000..e686d03400848ccda2e1917831b97dc59b68d014
--- /dev/null
+++ b/webkit/fileapi/sandbox_file_writer.cc
@@ -0,0 +1,248 @@
+// 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/fileapi/sandbox_file_writer.h"
+
+#include "base/file_util_proxy.h"
+#include "base/platform_file.h"
+#include "base/sequenced_task_runner.h"
+#include "net/base/io_buffer.h"
+#include "net/base/net_errors.h"
+#include "webkit/blob/local_file_reader.h"
+#include "webkit/fileapi/file_system_context.h"
+#include "webkit/fileapi/file_system_operation_interface.h"
+#include "webkit/fileapi/file_system_quota_util.h"
+#include "webkit/fileapi/file_system_util.h"
+#include "webkit/fileapi/local_file_writer.h"
+#include "webkit/quota/quota_manager.h"
+
+namespace fileapi {
+
+namespace {
+
+int PlatformFileErrorToNetError(base::PlatformFileError error) {
+ // TODO(kinuko): Move this static method to more convenient place.
+ return webkit_blob::LocalFileReader::PlatformFileErrorToNetError(error);
+}
+
+// Adjust the |quota| value in overwriting case (i.e. |file_size| > 0 and
+// |file_offset| < |file_size|) to make the remaining quota calculation easier.
+// Specifically this widens the quota for overlapping range (so that we can
+// simply compare written bytes against the adjusted quota).
+int64 AdjustQuotaForOverlap(int64 quota,
+ int64 file_offset,
+ int64 file_size) {
+ DCHECK_LE(file_offset, file_size);
+ if (quota < 0)
+ quota = 0;
+ int64 overlap = file_size - file_offset;
+ if (kint64max - overlap > quota)
+ quota += overlap;
+ return quota;
+}
+
+} // namespace
+
+SandboxFileWriter::SandboxFileWriter(
+ FileSystemContext* file_system_context,
+ const GURL& url,
+ int64 initial_offset)
+ : file_system_context_(file_system_context),
+ url_(url),
+ initial_offset_(initial_offset),
+ file_size_(0),
+ total_bytes_written_(0),
+ allowed_bytes_to_write_(0),
+ has_pending_operation_(false),
+ default_quota_(kint64max),
+ weak_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) {
+ const bool result = CrackFileSystemURL(
+ url_, &origin_, &file_system_type_, &virtual_path_);
+ DCHECK(result);
+}
+
+SandboxFileWriter::~SandboxFileWriter() {
+ if (quota_util())
+ quota_util()->proxy()->EndUpdateOrigin(origin_, file_system_type_);
+}
+
+int SandboxFileWriter::Write(
+ net::IOBuffer* buf, int buf_len,
+ const net::CompletionCallback& callback) {
+ has_pending_operation_ = true;
+ if (local_file_writer_.get())
+ return WriteInternal(buf, buf_len, callback);
+
+ FileSystemOperationInterface* operation =
+ file_system_context_->CreateFileSystemOperation(url_);
+ DCHECK(operation);
+ net::CompletionCallback write_task =
+ base::Bind(&SandboxFileWriter::DidInitializeForWrite,
+ weak_factory_.GetWeakPtr(),
+ make_scoped_refptr(buf), buf_len, callback);
+ operation->GetMetadata(
+ url_, base::Bind(&SandboxFileWriter::DidGetFileInfo,
+ weak_factory_.GetWeakPtr(), write_task));
+ return net::ERR_IO_PENDING;
+}
+
+int SandboxFileWriter::Cancel(const net::CompletionCallback& callback) {
+ if (!has_pending_operation_)
+ return net::ERR_UNEXPECTED;
+
+ DCHECK(!callback.is_null());
+ cancel_callback_ = callback;
+ return net::ERR_IO_PENDING;
+}
+
+int SandboxFileWriter::WriteInternal(
+ net::IOBuffer* buf, int buf_len,
+ const net::CompletionCallback& callback) {
+ // allowed_bytes_to_write could be negative if the file size is
+ // greater than the current (possibly new) quota.
+ DCHECK(total_bytes_written_ <= allowed_bytes_to_write_ ||
+ allowed_bytes_to_write_ < 0);
+ if (total_bytes_written_ >= allowed_bytes_to_write_) {
+ has_pending_operation_ = false;
+ return net::ERR_FILE_NO_SPACE;
+ }
+
+ if (buf_len > allowed_bytes_to_write_ - total_bytes_written_)
+ buf_len = allowed_bytes_to_write_ - total_bytes_written_;
+
+ DCHECK(local_file_writer_.get());
+ const int result = local_file_writer_->Write(
+ buf, buf_len,
+ base::Bind(&SandboxFileWriter::DidWrite, weak_factory_.GetWeakPtr(),
+ callback));
+ if (result != net::ERR_IO_PENDING)
+ has_pending_operation_ = false;
+ return result;
+}
+
+void SandboxFileWriter::DidGetFileInfo(
+ const net::CompletionCallback& callback,
+ base::PlatformFileError file_error,
+ const base::PlatformFileInfo& file_info,
+ const FilePath& platform_path) {
+ if (CancelIfRequested())
+ return;
+ if (file_error != base::PLATFORM_FILE_OK) {
+ callback.Run(PlatformFileErrorToNetError(file_error));
+ return;
+ }
+ if (file_info.is_directory) {
+ // We should not be writing to a directory.
+ callback.Run(net::ERR_ACCESS_DENIED);
+ return;
+ }
+ file_size_ = file_info.size;
+ if (initial_offset_ > file_size_) {
+ LOG(ERROR) << initial_offset_ << ", " << file_size_;
+ // This shouldn't happen as long as we check offset in the renderer.
+ NOTREACHED();
+ initial_offset_ = file_size_;
+ }
+ DCHECK(!local_file_writer_.get());
+ local_file_writer_.reset(new LocalFileWriter(platform_path, initial_offset_));
+
+ quota::QuotaManagerProxy* quota_manager_proxy =
+ file_system_context_->quota_manager_proxy();
+ if (!quota_manager_proxy || !quota_util()) {
+ // 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.
+ allowed_bytes_to_write_ = default_quota_;
+ callback.Run(net::OK);
+ return;
+ }
+
+ quota_util()->proxy()->StartUpdateOrigin(origin_, file_system_type_);
+ DCHECK(quota_manager_proxy->quota_manager());
+ quota_manager_proxy->quota_manager()->GetUsageAndQuota(
+ origin_,
+ FileSystemTypeToQuotaStorageType(file_system_type_),
+ base::Bind(&SandboxFileWriter::DidGetUsageAndQuota,
+ weak_factory_.GetWeakPtr(), callback));
+}
+
+void SandboxFileWriter::DidGetUsageAndQuota(
+ const net::CompletionCallback& callback,
+ quota::QuotaStatusCode status,
+ int64 usage, int64 quota) {
+ if (CancelIfRequested())
+ return;
+ if (status != quota::kQuotaStatusOk) {
+ LOG(WARNING) << "Got unexpected quota error : " << status;
+ callback.Run(net::ERR_FAILED);
+ return;
+ }
+
+ allowed_bytes_to_write_ = quota - usage;
+ callback.Run(net::OK);
+}
+
+void SandboxFileWriter::DidInitializeForWrite(
+ net::IOBuffer* buf, int buf_len,
+ const net::CompletionCallback& callback,
+ int init_status) {
+ if (CancelIfRequested())
+ return;
+ if (init_status != net::OK) {
+ has_pending_operation_ = false;
+ callback.Run(init_status);
+ return;
+ }
+ allowed_bytes_to_write_ = AdjustQuotaForOverlap(
+ allowed_bytes_to_write_, initial_offset_, file_size_);
+ const int result = WriteInternal(buf, buf_len, callback);
+ if (result != net::ERR_IO_PENDING)
+ callback.Run(result);
+}
+
+void SandboxFileWriter::DidWrite(
+ const net::CompletionCallback& callback,
+ int write_response) {
+ DCHECK(has_pending_operation_);
+ has_pending_operation_ = false;
+
+ if (write_response <= 0) {
+ if (CancelIfRequested())
+ return;
+ callback.Run(write_response);
+ return;
+ }
+
+ if (quota_util() &&
+ total_bytes_written_ + write_response + initial_offset_ > file_size_) {
+ int overlapped = file_size_ - total_bytes_written_ - initial_offset_;
+ if (overlapped < 0)
+ overlapped = 0;
+ quota_util()->proxy()->UpdateOriginUsage(
+ file_system_context_->quota_manager_proxy(),
+ origin_, file_system_type_, write_response - overlapped);
+ }
+ total_bytes_written_ += write_response;
+
+ if (CancelIfRequested())
+ return;
+ callback.Run(write_response);
+}
+
+bool SandboxFileWriter::CancelIfRequested() {
+ if (cancel_callback_.is_null())
+ return false;
+
+ net::CompletionCallback pending_cancel = cancel_callback_;
+ has_pending_operation_ = false;
+ cancel_callback_.Reset();
+ pending_cancel.Run(net::OK);
+ return true;
+}
+
+FileSystemQuotaUtil* SandboxFileWriter::quota_util() const {
+ DCHECK(file_system_context_.get());
+ return file_system_context_->GetQuotaUtil(file_system_type_);
+}
+
+} // namespace fileapi

Powered by Google App Engine
This is Rietveld 408576698