Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / chromeos / drive / file_system / copy_operation.cc
index 0804539..2300c31 100644 (file)
@@ -6,12 +6,12 @@
 
 #include <string>
 
-#include "base/file_util.h"
 #include "base/task_runner_util.h"
 #include "chrome/browser/chromeos/drive/drive.pb.h"
 #include "chrome/browser/chromeos/drive/file_cache.h"
+#include "chrome/browser/chromeos/drive/file_change.h"
 #include "chrome/browser/chromeos/drive/file_system/create_file_operation.h"
-#include "chrome/browser/chromeos/drive/file_system/operation_observer.h"
+#include "chrome/browser/chromeos/drive/file_system/operation_delegate.h"
 #include "chrome/browser/chromeos/drive/file_system_util.h"
 #include "chrome/browser/chromeos/drive/job_scheduler.h"
 #include "chrome/browser/chromeos/drive/resource_entry_conversion.h"
@@ -163,13 +163,13 @@ FileError TryToCopyLocally(internal::ResourceMetadata* metadata,
 FileError UpdateLocalStateForServerSideOperation(
     internal::ResourceMetadata* metadata,
     scoped_ptr<google_apis::FileResource> file_resource,
+    ResourceEntry* entry,
     base::FilePath* file_path) {
   DCHECK(file_resource);
 
-  ResourceEntry entry;
   std::string parent_resource_id;
-  if (!ConvertFileResourceToResourceEntry(*file_resource, &entry,
-                                          &parent_resource_id) ||
+  if (!ConvertFileResourceToResourceEntry(
+          *file_resource, entry, &parent_resource_id) ||
       parent_resource_id.empty())
     return FILE_ERROR_NOT_A_FILE;
 
@@ -178,14 +178,14 @@ FileError UpdateLocalStateForServerSideOperation(
                                                 &parent_local_id);
   if (error != FILE_ERROR_OK)
     return error;
-  entry.set_parent_local_id(parent_local_id);
+  entry->set_parent_local_id(parent_local_id);
 
   std::string local_id;
-  error = metadata->AddEntry(entry, &local_id);
+  error = metadata->AddEntry(*entry, &local_id);
   // Depending on timing, the metadata may have inserted via change list
   // already. So, FILE_ERROR_EXISTS is not an error.
   if (error == FILE_ERROR_EXISTS)
-    error = metadata->GetIdByResourceId(entry.resource_id(), &local_id);
+    error = metadata->GetIdByResourceId(entry->resource_id(), &local_id);
 
   if (error != FILE_ERROR_OK)
     return error;
@@ -200,13 +200,13 @@ FileError UpdateLocalStateForScheduleTransfer(
     internal::FileCache* cache,
     const base::FilePath& local_src_path,
     const base::FilePath& remote_dest_path,
+    ResourceEntry* entry,
     std::string* local_id) {
   FileError error = metadata->GetIdByPath(remote_dest_path, local_id);
   if (error != FILE_ERROR_OK)
     return error;
 
-  ResourceEntry entry;
-  error = metadata->GetResourceEntryById(*local_id, &entry);
+  error = metadata->GetResourceEntryById(*local_id, entry);
   if (error != FILE_ERROR_OK)
     return error;
 
@@ -233,7 +233,7 @@ FileError PrepareTransferFileFromLocalToRemote(
 
   // Try to parse GDoc File and extract the resource id, if necessary.
   // Failing isn't problem. It'd be handled as a regular file, then.
-  if (util::HasGDocFileExtension(local_src_path))
+  if (util::HasHostedDocumentExtension(local_src_path))
     *gdoc_resource_id = util::ReadResourceIdFromGDocFile(local_src_path);
   return FILE_ERROR_OK;
 }
@@ -275,19 +275,17 @@ FileError LocalWorkForTransferJsonGdocFile(
 }  // namespace
 
 CopyOperation::CopyOperation(base::SequencedTaskRunner* blocking_task_runner,
-                             OperationObserver* observer,
+                             OperationDelegate* delegate,
                              JobScheduler* scheduler,
                              internal::ResourceMetadata* metadata,
-                             internal::FileCache* cache,
-                             const ResourceIdCanonicalizer& id_canonicalizer)
+                             internal::FileCache* cache)
   : blocking_task_runner_(blocking_task_runner),
-    observer_(observer),
+    delegate_(delegate),
     scheduler_(scheduler),
     metadata_(metadata),
     cache_(cache),
-    id_canonicalizer_(id_canonicalizer),
     create_file_operation_(new CreateFileOperation(blocking_task_runner,
-                                                   observer,
+                                                   delegate,
                                                    metadata)),
     weak_ptr_factory_(this) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
@@ -334,31 +332,82 @@ void CopyOperation::CopyAfterTryToCopyLocally(
   DCHECK(!params->callback.is_null());
 
   for (size_t i = 0; i < updated_local_ids->size(); ++i)
-    observer_->OnEntryUpdatedByOperation((*updated_local_ids)[i]);
-
-  if (*directory_changed)
-    observer_->OnDirectoryChangedByOperation(params->dest_file_path.DirName());
+    delegate_->OnEntryUpdatedByOperation((*updated_local_ids)[i]);
+
+  if (*directory_changed) {
+    FileChange changed_file;
+    DCHECK(!params->src_entry.file_info().is_directory());
+    changed_file.Update(params->dest_file_path,
+                        FileChange::FILE_TYPE_FILE,
+                        FileChange::ADD_OR_UPDATE);
+    delegate_->OnFileChangedByOperation(changed_file);
+  }
 
   if (error != FILE_ERROR_OK || !*should_copy_on_server) {
     params->callback.Run(error);
     return;
   }
 
-  base::FilePath new_title = params->dest_file_path.BaseName();
-  if (params->src_entry.file_specific_info().is_hosted_document()) {
+  if (params->parent_entry.resource_id().empty()) {
+    // Parent entry may be being synced.
+    const bool waiting = delegate_->WaitForSyncComplete(
+        params->parent_entry.local_id(),
+        base::Bind(&CopyOperation::CopyAfterParentSync,
+                   weak_ptr_factory_.GetWeakPtr(), *params));
+    if (!waiting)
+      params->callback.Run(FILE_ERROR_NOT_FOUND);
+  } else {
+    CopyAfterGetParentResourceId(*params, &params->parent_entry, FILE_ERROR_OK);
+  }
+}
+
+void CopyOperation::CopyAfterParentSync(const CopyParams& params,
+                                        FileError error) {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+  DCHECK(!params.callback.is_null());
+
+  if (error != FILE_ERROR_OK) {
+    params.callback.Run(error);
+    return;
+  }
+
+  ResourceEntry* parent = new ResourceEntry;
+  base::PostTaskAndReplyWithResult(
+      blocking_task_runner_,
+      FROM_HERE,
+      base::Bind(&internal::ResourceMetadata::GetResourceEntryById,
+                 base::Unretained(metadata_),
+                 params.parent_entry.local_id(), parent),
+      base::Bind(&CopyOperation::CopyAfterGetParentResourceId,
+                 weak_ptr_factory_.GetWeakPtr(), params, base::Owned(parent)));
+}
+
+void CopyOperation::CopyAfterGetParentResourceId(const CopyParams& params,
+                                                 const ResourceEntry* parent,
+                                                 FileError error) {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+  DCHECK(!params.callback.is_null());
+
+  if (error != FILE_ERROR_OK) {
+    params.callback.Run(error);
+    return;
+  }
+
+  base::FilePath new_title = params.dest_file_path.BaseName();
+  if (params.src_entry.file_specific_info().is_hosted_document()) {
     // Drop the document extension, which should not be in the title.
     // TODO(yoshiki): Remove this code with crbug.com/223304.
     new_title = new_title.RemoveExtension();
   }
 
   base::Time last_modified =
-      params->preserve_last_modified ?
+      params.preserve_last_modified ?
       base::Time::FromInternalValue(
-          params->src_entry.file_info().last_modified()) : base::Time();
+          params.src_entry.file_info().last_modified()) : base::Time();
 
   CopyResourceOnServer(
-      params->src_entry.resource_id(), params->parent_entry.resource_id(),
-      new_title.AsUTF8Unsafe(), last_modified, params->callback);
+      params.src_entry.resource_id(), parent->resource_id(),
+      new_title.AsUTF8Unsafe(), last_modified, params.callback);
 }
 
 void CopyOperation::TransferFileFromLocalToRemote(
@@ -407,7 +456,7 @@ void CopyOperation::TransferFileFromLocalToRemoteAfterPrepare(
 
   // GDoc file may contain a resource ID in the old format.
   const std::string canonicalized_resource_id =
-      id_canonicalizer_.Run(*gdoc_resource_id);
+      util::CanonicalizeResourceId(*gdoc_resource_id);
 
   // Drop the document extension, which should not be in the title.
   // TODO(yoshiki): Remove this code with crbug.com/223304.
@@ -449,12 +498,19 @@ void CopyOperation::TransferJsonGdocFileAfterLocalWork(
     // When |resource_id| has no parent, we just set the new destination folder
     // as the parent, for sharing the document between the original source.
     // This reparenting is already done in LocalWorkForTransferJsonGdocFile().
-    case IS_ORPHAN:
+    case IS_ORPHAN: {
       DCHECK(!params->changed_path.empty());
-      observer_->OnEntryUpdatedByOperation(params->local_id);
-      observer_->OnDirectoryChangedByOperation(params->changed_path.DirName());
+      delegate_->OnEntryUpdatedByOperation(params->local_id);
+
+      FileChange changed_file;
+      changed_file.Update(
+          params->changed_path,
+          FileChange::FILE_TYPE_FILE,  // This must be a hosted document.
+          FileChange::ADD_OR_UPDATE);
+      delegate_->OnFileChangedByOperation(changed_file);
       params->callback.Run(error);
       break;
+    }
     // When the |resource_id| is not in the local metadata, assume it to be a
     // document just now shared on the server but not synced locally.
     // Same as the IS_ORPHAN case, we want to deal the case by setting parent,
@@ -503,6 +559,8 @@ void CopyOperation::UpdateAfterServerSideOperation(
     return;
   }
 
+  ResourceEntry* resource_entry = new ResourceEntry;
+
   // The copy on the server side is completed successfully. Update the local
   // metadata.
   base::FilePath* file_path = new base::FilePath;
@@ -510,21 +568,30 @@ void CopyOperation::UpdateAfterServerSideOperation(
       blocking_task_runner_.get(),
       FROM_HERE,
       base::Bind(&UpdateLocalStateForServerSideOperation,
-                 metadata_, base::Passed(&entry), file_path),
+                 metadata_,
+                 base::Passed(&entry),
+                 resource_entry,
+                 file_path),
       base::Bind(&CopyOperation::UpdateAfterLocalStateUpdate,
                  weak_ptr_factory_.GetWeakPtr(),
-                 callback, base::Owned(file_path)));
+                 callback,
+                 base::Owned(file_path),
+                 base::Owned(resource_entry)));
 }
 
 void CopyOperation::UpdateAfterLocalStateUpdate(
     const FileOperationCallback& callback,
     base::FilePath* file_path,
+    const ResourceEntry* entry,
     FileError error) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
   DCHECK(!callback.is_null());
 
-  if (error == FILE_ERROR_OK)
-    observer_->OnDirectoryChangedByOperation(file_path->DirName());
+  if (error == FILE_ERROR_OK) {
+    FileChange changed_file;
+    changed_file.Update(*file_path, *entry, FileChange::ADD_OR_UPDATE);
+    delegate_->OnFileChangedByOperation(changed_file);
+  }
   callback.Run(error);
 }
 
@@ -558,29 +625,40 @@ void CopyOperation::ScheduleTransferRegularFileAfterCreate(
   }
 
   std::string* local_id = new std::string;
+  ResourceEntry* entry = new ResourceEntry;
   base::PostTaskAndReplyWithResult(
       blocking_task_runner_.get(),
       FROM_HERE,
-      base::Bind(
-          &UpdateLocalStateForScheduleTransfer,
-          metadata_, cache_, local_src_path, remote_dest_path, local_id),
+      base::Bind(&UpdateLocalStateForScheduleTransfer,
+                 metadata_,
+                 cache_,
+                 local_src_path,
+                 remote_dest_path,
+                 entry,
+                 local_id),
       base::Bind(
           &CopyOperation::ScheduleTransferRegularFileAfterUpdateLocalState,
-          weak_ptr_factory_.GetWeakPtr(), callback, remote_dest_path,
+          weak_ptr_factory_.GetWeakPtr(),
+          callback,
+          remote_dest_path,
+          base::Owned(entry),
           base::Owned(local_id)));
 }
 
 void CopyOperation::ScheduleTransferRegularFileAfterUpdateLocalState(
     const FileOperationCallback& callback,
     const base::FilePath& remote_dest_path,
+    const ResourceEntry* entry,
     std::string* local_id,
     FileError error) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
   DCHECK(!callback.is_null());
 
   if (error == FILE_ERROR_OK) {
-    observer_->OnDirectoryChangedByOperation(remote_dest_path.DirName());
-    observer_->OnEntryUpdatedByOperation(*local_id);
+    FileChange changed_file;
+    changed_file.Update(remote_dest_path, *entry, FileChange::ADD_OR_UPDATE);
+    delegate_->OnFileChangedByOperation(changed_file);
+    delegate_->OnEntryUpdatedByOperation(*local_id);
   }
   callback.Run(error);
 }