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

Unified Diff: webkit/fileapi/cross_operation_delegate.cc

Issue 12051010: (For-try) Divide recursive Copy/Move into multiple async tasks (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: test fix Created 7 years, 11 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/cross_operation_delegate.cc
diff --git a/webkit/fileapi/cross_operation_delegate.cc b/webkit/fileapi/cross_operation_delegate.cc
new file mode 100644
index 0000000000000000000000000000000000000000..73c0e4dc4a1d6c43191ddcf573e5346c52eea4d7
--- /dev/null
+++ b/webkit/fileapi/cross_operation_delegate.cc
@@ -0,0 +1,264 @@
+// Copyright (c) 2013 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/cross_operation_delegate.h"
+
+#include "base/bind.h"
+#include "webkit/blob/shareable_file_reference.h"
+#include "webkit/fileapi/file_system_context.h"
+#include "webkit/fileapi/file_system_operation_context.h"
+#include "webkit/fileapi/local_file_system_operation.h"
+
+namespace fileapi {
+
+CrossOperationDelegate::CrossOperationDelegate(
+ LocalFileSystemOperation* original_operation,
+ const FileSystemURL& src_root,
+ const FileSystemURL& dest_root,
+ OperationType operation_type,
+ const StatusCallback& callback)
+ : RecursiveOperationDelegate(original_operation),
+ src_root_(src_root),
+ dest_root_(dest_root),
+ operation_type_(operation_type),
+ callback_(callback),
+ src_root_operation_(NULL) {
+ same_file_system_ =
+ src_root_.origin() == dest_root_.origin() &&
+ src_root_.type() == dest_root_.type();
+}
+
+CrossOperationDelegate::~CrossOperationDelegate() {
+ if (src_root_operation_)
+ delete src_root_operation_;
+}
+
+void CrossOperationDelegate::Run() {
+ // Not supported; this should never be called.
+ NOTREACHED();
+}
+
+void CrossOperationDelegate::RunRecursively() {
+ // Perform light-weight checks first.
+
+ // It is an error to try to copy/move an entry into its child.
+ if (same_file_system_ && src_root_.path().IsParent(dest_root_.path())) {
+ callback_.Run(base::PLATFORM_FILE_ERROR_INVALID_OPERATION);
+ return;
+ }
+
+ // It is an error to copy/move an entry into the same path.
+ if (same_file_system_ && src_root_.path() == dest_root_.path()) {
+ callback_.Run(base::PLATFORM_FILE_ERROR_EXISTS);
+ return;
+ }
+
+ // Initialize the src_root_operation_ for the src root URL.
+ DCHECK(!src_root_operation_);
+ if (!same_file_system_) {
+ base::PlatformFileError error = base::PLATFORM_FILE_OK;
+ FileSystemOperation* operation = file_system_context()->
+ CreateFileSystemOperation(src_root_, &error);
+ if (error != base::PLATFORM_FILE_OK) {
+ DCHECK(!operation);
+ callback_.Run(error);
+ return;
+ }
+ src_root_operation_ = operation->AsLocalFileSystemOperation();
+ DCHECK(src_root_operation_);
+ }
+
+ // First try to copy/move it as a file.
+ CopyOrMoveFile(src_root_, dest_root_,
+ base::Bind(&CrossOperationDelegate::DidTryCopyOrMoveFile,
+ AsWeakPtr()));
+}
+
+void CrossOperationDelegate::ProcessFile(const FileSystemURL& src_url,
+ const StatusCallback& callback) {
+ CopyOrMoveFile(src_url, CreateDestURL(src_url), callback);
+}
+
+void CrossOperationDelegate::ProcessDirectory(const FileSystemURL& src_url,
+ const StatusCallback& callback) {
+ FileSystemURL dest_url = CreateDestURL(src_url);
+ LocalFileSystemOperation* dest_operation = NewDestOperation(dest_url);
+ if (!dest_operation) {
+ return;
+ }
+
+ // If operation_type == Move we may need to record directories and
+ // restore directory timestamps in the end, though it may have
+ // negative performance impact.
+ // See http://crbug.com/171284 for more details.
+ dest_operation->CreateDirectory(
+ dest_url, false /* exclusive */, false /* recursive */, callback);
+}
+
+void CrossOperationDelegate::DidTryCopyOrMoveFile(
+ base::PlatformFileError error) {
+ if (error == base::PLATFORM_FILE_OK ||
+ error != base::PLATFORM_FILE_ERROR_NOT_A_FILE) {
+ callback_.Run(error);
+ return;
+ }
+
+ // The src_root_ looks to be a directory.
+ // Try removing the dest_root_ to see if it exists and/or it is an
+ // empty directory.
+ LocalFileSystemOperation* dest_operation = NewDestOperation(dest_root_);
+ if (!dest_operation)
+ return;
+ dest_operation->RemoveDirectory(
+ dest_root_, base::Bind(&CrossOperationDelegate::DidTryRemoveDestRoot,
+ AsWeakPtr()));
+}
+
+void CrossOperationDelegate::DidTryRemoveDestRoot(
+ base::PlatformFileError error) {
+ if (error == base::PLATFORM_FILE_ERROR_NOT_A_DIRECTORY) {
+ callback_.Run(base::PLATFORM_FILE_ERROR_INVALID_OPERATION);
+ return;
+ }
+ if (error != base::PLATFORM_FILE_OK &&
+ error != base::PLATFORM_FILE_ERROR_NOT_FOUND) {
+ callback_.Run(error);
+ return;
+ }
+
+ // Start to process the source directory recursively.
+ StartRecursiveOperation(
+ src_root_, base::Bind(&CrossOperationDelegate::DidFinishCopy,
+ AsWeakPtr(), src_root_, callback_));
+}
+
+void CrossOperationDelegate::CopyOrMoveFile(
+ const FileSystemURL& src,
+ const FileSystemURL& dest,
+ const StatusCallback& callback) {
+ LocalFileSystemOperation* src_operation = NewSourceOperation(src);
+ if (!src_operation)
+ return;
+
+ // Same filesystem case.
+ if (same_file_system_) {
ericu 2013/01/23 19:27:23 I'm getting a bit lost in all the redirection. If
+ if (operation_type_ == OPERATION_MOVE)
+ src_operation->MoveLocalFile(src, dest, callback);
+ else
+ src_operation->CopyLocalFile(src, dest, callback);
+ return;
+ }
+
+ // Cross filesystem case.
+ // Performs CreateSnapshotFile, CopyInForeignFile and then calls
+ // copy_callback which removes the source file if operation_type == MOVE.
+ StatusCallback copy_callback =
+ base::Bind(&CrossOperationDelegate::DidFinishCopy, AsWeakPtr(),
+ src, callback);
+ src_operation->CreateSnapshotFile(
+ src, base::Bind(&CrossOperationDelegate::DidCreateSnapshot, AsWeakPtr(),
+ dest, copy_callback));
+}
+
+void CrossOperationDelegate::DidCreateSnapshot(
+ const FileSystemURL& dest,
+ const StatusCallback& callback,
+ base::PlatformFileError error,
+ const base::PlatformFileInfo& file_info,
+ const FilePath& platform_path,
+ const scoped_refptr<webkit_blob::ShareableFileReference>& file_ref) {
+ if (error != base::PLATFORM_FILE_OK) {
+ callback.Run(error);
+ return;
+ }
+ current_file_ref_ = file_ref;
+
+ // For now we assume CreateSnapshotFile always return a valid local file path.
+ // TODO(kinuko): Otherwise create a FileStreamReader to perform a copy/move.
+ DCHECK(!platform_path.empty());
+
+ LocalFileSystemOperation* dest_operation = NewDestOperation(dest);
+ if (!dest_operation)
+ return;
+ dest_operation->CopyInForeignFile(platform_path, dest, callback);
+}
+
+void CrossOperationDelegate::DidFinishCopy(
+ const FileSystemURL& src,
+ const StatusCallback& callback,
+ base::PlatformFileError error) {
+ if (error != base::PLATFORM_FILE_OK ||
+ operation_type_ == OPERATION_COPY) {
+ callback.Run(error);
+ return;
+ }
+
+ DCHECK_EQ(OPERATION_MOVE, operation_type_);
+
+ // Remove the source for finalizing move oepration.
ericu 2013/01/23 19:27:23 typo: operation
+ LocalFileSystemOperation* src_operation = NewSourceOperation(src);
+ if (!src_operation)
+ return;
+ src_operation->Remove(
+ src_root_, true /* recursive */,
+ base::Bind(&CrossOperationDelegate::DidRemoveSourceForMove,
+ AsWeakPtr(), callback));
+}
+
+void CrossOperationDelegate::DidRemoveSourceForMove(
+ const StatusCallback& callback,
+ base::PlatformFileError error) {
+ if (error == base::PLATFORM_FILE_ERROR_NOT_FOUND)
+ error = base::PLATFORM_FILE_OK;
+ callback.Run(error);
+}
+
+FileSystemURL CrossOperationDelegate::CreateDestURL(
+ const FileSystemURL& src_url) const {
+ DCHECK_EQ(src_root_.type(), src_url.type());
+ DCHECK_EQ(src_root_.origin(), src_url.origin());
+
+ FilePath path = dest_root_.path();
+ src_root_.path().AppendRelativePath(src_url.path(), &path);
+ return dest_root_.WithPath(path);
+}
+
+LocalFileSystemOperation* CrossOperationDelegate::NewDestOperation(
+ const FileSystemURL& url) {
+ base::PlatformFileError error = base::PLATFORM_FILE_OK;
+ LocalFileSystemOperation* operation =
+ RecursiveOperationDelegate::NewOperation(url, &error);
+ if (!operation) {
+ DCHECK_NE(base::PLATFORM_FILE_OK, error);
+ callback_.Run(error);
+ return NULL;
+ }
+ return operation;
+}
+
+LocalFileSystemOperation* CrossOperationDelegate::NewSourceOperation(
+ const FileSystemURL& url) {
+ if (same_file_system_)
+ return NewDestOperation(url);
+
+ base::PlatformFileError error = base::PLATFORM_FILE_OK;
+ FileSystemOperation* operation = file_system_context()->
+ CreateFileSystemOperation(url, &error);
+ if (!operation) {
+ DCHECK_NE(base::PLATFORM_FILE_OK, error);
+ callback_.Run(error);
+ return NULL;
+ }
+ LocalFileSystemOperation* local_operation =
+ operation->AsLocalFileSystemOperation();
+ DCHECK(local_operation);
+ DCHECK(src_root_operation_);
+
+ // Let the new operation inherit from the root operation.
+ local_operation->set_overriding_operation_context(
+ src_root_operation_->operation_context());
+ return local_operation;
+}
+
+} // namespace fileapi

Powered by Google App Engine
This is Rietveld 408576698