| Index: chrome/browser/chromeos/drive/file_system/copy_operation.cc
 | 
| diff --git a/chrome/browser/chromeos/drive/file_system/copy_operation.cc b/chrome/browser/chromeos/drive/file_system/copy_operation.cc
 | 
| index 6d987af1c4091ee7c9ea53f875364e511757e05f..099fe428169c8f7b18475717d28c9773a81f855b 100644
 | 
| --- a/chrome/browser/chromeos/drive/file_system/copy_operation.cc
 | 
| +++ b/chrome/browser/chromeos/drive/file_system/copy_operation.cc
 | 
| @@ -25,31 +25,100 @@ using content::BrowserThread;
 | 
|  namespace drive {
 | 
|  namespace file_system {
 | 
|  
 | 
| +struct CopyOperation::CopyParams {
 | 
| +  base::FilePath src_file_path;
 | 
| +  base::FilePath dest_file_path;
 | 
| +  bool preserve_last_modified;
 | 
| +  FileOperationCallback callback;
 | 
| +  ResourceEntry src_entry;
 | 
| +  ResourceEntry parent_entry;
 | 
| +};
 | 
| +
 | 
|  namespace {
 | 
|  
 | 
| -FileError PrepareCopy(internal::ResourceMetadata* metadata,
 | 
| -                      const base::FilePath& src_path,
 | 
| -                      const base::FilePath& dest_path,
 | 
| -                      ResourceEntry* src_entry,
 | 
| -                      std::string* parent_resource_id) {
 | 
| -  FileError error = metadata->GetResourceEntryByPath(src_path, src_entry);
 | 
| +FileError TryToCopyLocally(internal::ResourceMetadata* metadata,
 | 
| +                           internal::FileCache* cache,
 | 
| +                           CopyOperation::CopyParams* params,
 | 
| +                           std::vector<std::string>* updated_local_ids,
 | 
| +                           bool* directory_changed,
 | 
| +                           bool* should_copy_on_server) {
 | 
| +  FileError error = metadata->GetResourceEntryByPath(params->src_file_path,
 | 
| +                                                     ¶ms->src_entry);
 | 
|    if (error != FILE_ERROR_OK)
 | 
|      return error;
 | 
|  
 | 
| -  ResourceEntry parent_entry;
 | 
| -  error = metadata->GetResourceEntryByPath(dest_path.DirName(), &parent_entry);
 | 
| +  error = metadata->GetResourceEntryByPath(params->dest_file_path.DirName(),
 | 
| +                                           ¶ms->parent_entry);
 | 
|    if (error != FILE_ERROR_OK)
 | 
|      return error;
 | 
|  
 | 
| -  if (!parent_entry.file_info().is_directory())
 | 
| +  if (!params->parent_entry.file_info().is_directory())
 | 
|      return FILE_ERROR_NOT_A_DIRECTORY;
 | 
|  
 | 
|    // Drive File System doesn't support recursive copy.
 | 
| -  if (src_entry->file_info().is_directory())
 | 
| +  if (params->src_entry.file_info().is_directory())
 | 
|      return FILE_ERROR_NOT_A_FILE;
 | 
|  
 | 
| -  *parent_resource_id = parent_entry.resource_id();
 | 
| -  return FILE_ERROR_OK;
 | 
| +  // Check destination.
 | 
| +  ResourceEntry dest_entry;
 | 
| +  error = metadata->GetResourceEntryByPath(params->dest_file_path, &dest_entry);
 | 
| +  switch (error) {
 | 
| +    case FILE_ERROR_OK:
 | 
| +      // File API spec says it is an error to try to "copy a file to a path
 | 
| +      // occupied by a directory".
 | 
| +      if (dest_entry.file_info().is_directory())
 | 
| +        return FILE_ERROR_INVALID_OPERATION;
 | 
| +
 | 
| +      // Move the existing entry to the trash.
 | 
| +      dest_entry.set_parent_local_id(util::kDriveTrashDirLocalId);
 | 
| +      error = metadata->RefreshEntry(dest_entry);
 | 
| +      if (error != FILE_ERROR_OK)
 | 
| +        return error;
 | 
| +      updated_local_ids->push_back(dest_entry.local_id());
 | 
| +      *directory_changed = true;
 | 
| +      break;
 | 
| +    case FILE_ERROR_NOT_FOUND:
 | 
| +      break;
 | 
| +    default:
 | 
| +      return error;
 | 
| +  }
 | 
| +
 | 
| +  // If the entry exists on the server and the cache file is not dirty,
 | 
| +  // server side copy can be used.
 | 
| +  FileCacheEntry cache_entry;
 | 
| +  cache->GetCacheEntry(params->src_entry.local_id(), &cache_entry);
 | 
| +  if (!params->src_entry.resource_id().empty() && !cache_entry.is_dirty()) {
 | 
| +    *should_copy_on_server = true;
 | 
| +    return FILE_ERROR_OK;
 | 
| +  }
 | 
| +
 | 
| +  // Copy locally.
 | 
| +  ResourceEntry entry;
 | 
| +  const int64 now = base::Time::Now().ToInternalValue();
 | 
| +  entry.set_title(params->dest_file_path.BaseName().AsUTF8Unsafe());
 | 
| +  entry.set_parent_local_id(params->parent_entry.local_id());
 | 
| +  entry.mutable_file_specific_info()->set_content_mime_type(
 | 
| +      params->src_entry.file_specific_info().content_mime_type());
 | 
| +  entry.set_metadata_edit_state(ResourceEntry::DIRTY);
 | 
| +  entry.mutable_file_info()->set_last_modified(
 | 
| +      params->preserve_last_modified ?
 | 
| +      params->src_entry.file_info().last_modified() : now);
 | 
| +  entry.mutable_file_info()->set_last_accessed(now);
 | 
| +
 | 
| +  std::string local_id;
 | 
| +  error = metadata->AddEntry(entry, &local_id);
 | 
| +  if (error != FILE_ERROR_OK)
 | 
| +    return error;
 | 
| +  updated_local_ids->push_back(local_id);
 | 
| +  *directory_changed = true;
 | 
| +
 | 
| +  base::FilePath cache_file_path;
 | 
| +  error = cache->GetFile(params->src_entry.local_id(), &cache_file_path);
 | 
| +  if (error != FILE_ERROR_OK)
 | 
| +    return error;
 | 
| +
 | 
| +  return cache->Store(local_id, std::string(), cache_file_path,
 | 
| +                      internal::FileCache::FILE_OPERATION_COPY);
 | 
|  }
 | 
|  
 | 
|  int64 GetFileSize(const base::FilePath& file_path) {
 | 
| @@ -143,12 +212,6 @@ FileError PrepareTransferFileFromLocalToRemote(
 | 
|  
 | 
|  }  // namespace
 | 
|  
 | 
| -struct CopyOperation::CopyParams {
 | 
| -  base::FilePath dest_file_path;
 | 
| -  bool preserve_last_modified;
 | 
| -  FileOperationCallback callback;
 | 
| -};
 | 
| -
 | 
|  CopyOperation::CopyOperation(base::SequencedTaskRunner* blocking_task_runner,
 | 
|                               OperationObserver* observer,
 | 
|                               JobScheduler* scheduler,
 | 
| @@ -181,51 +244,61 @@ void CopyOperation::Copy(const base::FilePath& src_file_path,
 | 
|    DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
 | 
|    DCHECK(!callback.is_null());
 | 
|  
 | 
| -  CopyParams params;
 | 
| -  params.dest_file_path = dest_file_path;
 | 
| -  params.preserve_last_modified = preserve_last_modified;
 | 
| -  params.callback = callback;
 | 
| +  CopyParams* params = new CopyParams;
 | 
| +  params->src_file_path = src_file_path;
 | 
| +  params->dest_file_path = dest_file_path;
 | 
| +  params->preserve_last_modified = preserve_last_modified;
 | 
| +  params->callback = callback;
 | 
|  
 | 
| -  ResourceEntry* src_entry = new ResourceEntry;
 | 
| -  std::string* parent_resource_id = new std::string;
 | 
| +  std::vector<std::string>* updated_local_ids = new std::vector<std::string>;
 | 
| +  bool* directory_changed = new bool(false);
 | 
| +  bool* should_copy_on_server = new bool(false);
 | 
|    base::PostTaskAndReplyWithResult(
 | 
|        blocking_task_runner_.get(),
 | 
|        FROM_HERE,
 | 
| -      base::Bind(&PrepareCopy,
 | 
| -                 metadata_, src_file_path, dest_file_path,
 | 
| -                 src_entry, parent_resource_id),
 | 
| -      base::Bind(&CopyOperation::CopyAfterPrepare,
 | 
| -                 weak_ptr_factory_.GetWeakPtr(), params,
 | 
| -                 base::Owned(src_entry), base::Owned(parent_resource_id)));
 | 
| +      base::Bind(&TryToCopyLocally, metadata_, cache_, params,
 | 
| +                 updated_local_ids, directory_changed, should_copy_on_server),
 | 
| +      base::Bind(&CopyOperation::CopyAfterTryToCopyLocally,
 | 
| +                 weak_ptr_factory_.GetWeakPtr(), base::Owned(params),
 | 
| +                 base::Owned(updated_local_ids), base::Owned(directory_changed),
 | 
| +                 base::Owned(should_copy_on_server)));
 | 
|  }
 | 
|  
 | 
| -void CopyOperation::CopyAfterPrepare(const CopyParams& params,
 | 
| -                                     ResourceEntry* src_entry,
 | 
| -                                     std::string* parent_resource_id,
 | 
| -                                     FileError error) {
 | 
| +void CopyOperation::CopyAfterTryToCopyLocally(
 | 
| +    const CopyParams* params,
 | 
| +    const std::vector<std::string>* updated_local_ids,
 | 
| +    const bool* directory_changed,
 | 
| +    const bool* should_copy_on_server,
 | 
| +    FileError error) {
 | 
|    DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
 | 
| -  DCHECK(!params.callback.is_null());
 | 
| +  DCHECK(!params->callback.is_null());
 | 
|  
 | 
| -  if (error != FILE_ERROR_OK) {
 | 
| -    params.callback.Run(error);
 | 
| +  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());
 | 
| +
 | 
| +  if (error != FILE_ERROR_OK || !*should_copy_on_server) {
 | 
| +    params->callback.Run(error);
 | 
|      return;
 | 
|    }
 | 
|  
 | 
| -  base::FilePath new_title = params.dest_file_path.BaseName();
 | 
| -  if (src_entry->file_specific_info().is_hosted_document()) {
 | 
| +  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 ?
 | 
| -      base::Time::FromInternalValue(src_entry->file_info().last_modified()) :
 | 
| -      base::Time();
 | 
| +      params->preserve_last_modified ?
 | 
| +      base::Time::FromInternalValue(
 | 
| +          params->src_entry.file_info().last_modified()) : base::Time();
 | 
|  
 | 
|    CopyResourceOnServer(
 | 
| -      src_entry->resource_id(), *parent_resource_id,
 | 
| -      new_title.AsUTF8Unsafe(), last_modified, params.callback);
 | 
| +      params->src_entry.resource_id(), params->parent_entry.resource_id(),
 | 
| +      new_title.AsUTF8Unsafe(), last_modified, params->callback);
 | 
|  }
 | 
|  
 | 
|  void CopyOperation::TransferFileFromLocalToRemote(
 | 
| 
 |