| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/browser/chromeos/drive/file_system/copy_operation.h" | 5 #include "chrome/browser/chromeos/drive/file_system/copy_operation.h" |
| 6 | 6 |
| 7 #include <string> | 7 #include <string> |
| 8 | 8 |
| 9 #include "base/file_util.h" | 9 #include "base/file_util.h" |
| 10 #include "base/task_runner_util.h" | 10 #include "base/task_runner_util.h" |
| 11 #include "chrome/browser/chromeos/drive/drive.pb.h" | 11 #include "chrome/browser/chromeos/drive/drive.pb.h" |
| 12 #include "chrome/browser/chromeos/drive/file_cache.h" | 12 #include "chrome/browser/chromeos/drive/file_cache.h" |
| 13 #include "chrome/browser/chromeos/drive/file_system/create_file_operation.h" | 13 #include "chrome/browser/chromeos/drive/file_system/create_file_operation.h" |
| 14 #include "chrome/browser/chromeos/drive/file_system/operation_observer.h" | 14 #include "chrome/browser/chromeos/drive/file_system/operation_observer.h" |
| 15 #include "chrome/browser/chromeos/drive/file_system_util.h" | 15 #include "chrome/browser/chromeos/drive/file_system_util.h" |
| 16 #include "chrome/browser/chromeos/drive/job_scheduler.h" | 16 #include "chrome/browser/chromeos/drive/job_scheduler.h" |
| 17 #include "chrome/browser/chromeos/drive/resource_entry_conversion.h" | 17 #include "chrome/browser/chromeos/drive/resource_entry_conversion.h" |
| 18 #include "chrome/browser/chromeos/drive/resource_metadata.h" | 18 #include "chrome/browser/chromeos/drive/resource_metadata.h" |
| 19 #include "chrome/browser/drive/drive_api_util.h" | 19 #include "chrome/browser/drive/drive_api_util.h" |
| 20 #include "content/public/browser/browser_thread.h" | 20 #include "content/public/browser/browser_thread.h" |
| 21 #include "google_apis/drive/drive_api_parser.h" | 21 #include "google_apis/drive/drive_api_parser.h" |
| 22 | 22 |
| 23 using content::BrowserThread; | 23 using content::BrowserThread; |
| 24 | 24 |
| 25 namespace drive { | 25 namespace drive { |
| 26 namespace file_system { | 26 namespace file_system { |
| 27 | 27 |
| 28 struct CopyOperation::CopyParams { |
| 29 base::FilePath src_file_path; |
| 30 base::FilePath dest_file_path; |
| 31 bool preserve_last_modified; |
| 32 FileOperationCallback callback; |
| 33 ResourceEntry src_entry; |
| 34 ResourceEntry parent_entry; |
| 35 }; |
| 36 |
| 28 namespace { | 37 namespace { |
| 29 | 38 |
| 30 FileError PrepareCopy(internal::ResourceMetadata* metadata, | 39 FileError TryToCopyLocally(internal::ResourceMetadata* metadata, |
| 31 const base::FilePath& src_path, | 40 internal::FileCache* cache, |
| 32 const base::FilePath& dest_path, | 41 CopyOperation::CopyParams* params, |
| 33 ResourceEntry* src_entry, | 42 std::vector<std::string>* updated_local_ids, |
| 34 std::string* parent_resource_id) { | 43 bool* directory_changed, |
| 35 FileError error = metadata->GetResourceEntryByPath(src_path, src_entry); | 44 bool* should_copy_on_server) { |
| 45 FileError error = metadata->GetResourceEntryByPath(params->src_file_path, |
| 46 ¶ms->src_entry); |
| 36 if (error != FILE_ERROR_OK) | 47 if (error != FILE_ERROR_OK) |
| 37 return error; | 48 return error; |
| 38 | 49 |
| 39 ResourceEntry parent_entry; | 50 error = metadata->GetResourceEntryByPath(params->dest_file_path.DirName(), |
| 40 error = metadata->GetResourceEntryByPath(dest_path.DirName(), &parent_entry); | 51 ¶ms->parent_entry); |
| 41 if (error != FILE_ERROR_OK) | 52 if (error != FILE_ERROR_OK) |
| 42 return error; | 53 return error; |
| 43 | 54 |
| 44 if (!parent_entry.file_info().is_directory()) | 55 if (!params->parent_entry.file_info().is_directory()) |
| 45 return FILE_ERROR_NOT_A_DIRECTORY; | 56 return FILE_ERROR_NOT_A_DIRECTORY; |
| 46 | 57 |
| 47 // Drive File System doesn't support recursive copy. | 58 // Drive File System doesn't support recursive copy. |
| 48 if (src_entry->file_info().is_directory()) | 59 if (params->src_entry.file_info().is_directory()) |
| 49 return FILE_ERROR_NOT_A_FILE; | 60 return FILE_ERROR_NOT_A_FILE; |
| 50 | 61 |
| 51 *parent_resource_id = parent_entry.resource_id(); | 62 // Check destination. |
| 52 return FILE_ERROR_OK; | 63 ResourceEntry dest_entry; |
| 64 error = metadata->GetResourceEntryByPath(params->dest_file_path, &dest_entry); |
| 65 switch (error) { |
| 66 case FILE_ERROR_OK: |
| 67 // File API spec says it is an error to try to "copy a file to a path |
| 68 // occupied by a directory". |
| 69 if (dest_entry.file_info().is_directory()) |
| 70 return FILE_ERROR_INVALID_OPERATION; |
| 71 |
| 72 // Move the existing entry to the trash. |
| 73 dest_entry.set_parent_local_id(util::kDriveTrashDirLocalId); |
| 74 error = metadata->RefreshEntry(dest_entry); |
| 75 if (error != FILE_ERROR_OK) |
| 76 return error; |
| 77 updated_local_ids->push_back(dest_entry.local_id()); |
| 78 *directory_changed = true; |
| 79 break; |
| 80 case FILE_ERROR_NOT_FOUND: |
| 81 break; |
| 82 default: |
| 83 return error; |
| 84 } |
| 85 |
| 86 // If the entry exists on the server and the cache file is not dirty, |
| 87 // server side copy can be used. |
| 88 FileCacheEntry cache_entry; |
| 89 cache->GetCacheEntry(params->src_entry.local_id(), &cache_entry); |
| 90 if (!params->src_entry.resource_id().empty() && !cache_entry.is_dirty()) { |
| 91 *should_copy_on_server = true; |
| 92 return FILE_ERROR_OK; |
| 93 } |
| 94 |
| 95 // Copy locally. |
| 96 ResourceEntry entry; |
| 97 const int64 now = base::Time::Now().ToInternalValue(); |
| 98 entry.set_title(params->dest_file_path.BaseName().AsUTF8Unsafe()); |
| 99 entry.set_parent_local_id(params->parent_entry.local_id()); |
| 100 entry.mutable_file_specific_info()->set_content_mime_type( |
| 101 params->src_entry.file_specific_info().content_mime_type()); |
| 102 entry.set_metadata_edit_state(ResourceEntry::DIRTY); |
| 103 entry.mutable_file_info()->set_last_modified( |
| 104 params->preserve_last_modified ? |
| 105 params->src_entry.file_info().last_modified() : now); |
| 106 entry.mutable_file_info()->set_last_accessed(now); |
| 107 |
| 108 std::string local_id; |
| 109 error = metadata->AddEntry(entry, &local_id); |
| 110 if (error != FILE_ERROR_OK) |
| 111 return error; |
| 112 updated_local_ids->push_back(local_id); |
| 113 *directory_changed = true; |
| 114 |
| 115 base::FilePath cache_file_path; |
| 116 error = cache->GetFile(params->src_entry.local_id(), &cache_file_path); |
| 117 if (error != FILE_ERROR_OK) |
| 118 return error; |
| 119 |
| 120 return cache->Store(local_id, std::string(), cache_file_path, |
| 121 internal::FileCache::FILE_OPERATION_COPY); |
| 53 } | 122 } |
| 54 | 123 |
| 55 int64 GetFileSize(const base::FilePath& file_path) { | 124 int64 GetFileSize(const base::FilePath& file_path) { |
| 56 int64 file_size; | 125 int64 file_size; |
| 57 if (!base::GetFileSize(file_path, &file_size)) | 126 if (!base::GetFileSize(file_path, &file_size)) |
| 58 return -1; | 127 return -1; |
| 59 return file_size; | 128 return file_size; |
| 60 } | 129 } |
| 61 | 130 |
| 62 // Stores the copied entry and returns its path. | 131 // Stores the copied entry and returns its path. |
| (...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 136 if (util::HasGDocFileExtension(local_src_path)) { | 205 if (util::HasGDocFileExtension(local_src_path)) { |
| 137 *gdoc_resource_id = util::ReadResourceIdFromGDocFile(local_src_path); | 206 *gdoc_resource_id = util::ReadResourceIdFromGDocFile(local_src_path); |
| 138 *parent_resource_id = parent_entry.resource_id(); | 207 *parent_resource_id = parent_entry.resource_id(); |
| 139 } | 208 } |
| 140 | 209 |
| 141 return FILE_ERROR_OK; | 210 return FILE_ERROR_OK; |
| 142 } | 211 } |
| 143 | 212 |
| 144 } // namespace | 213 } // namespace |
| 145 | 214 |
| 146 struct CopyOperation::CopyParams { | |
| 147 base::FilePath dest_file_path; | |
| 148 bool preserve_last_modified; | |
| 149 FileOperationCallback callback; | |
| 150 }; | |
| 151 | |
| 152 CopyOperation::CopyOperation(base::SequencedTaskRunner* blocking_task_runner, | 215 CopyOperation::CopyOperation(base::SequencedTaskRunner* blocking_task_runner, |
| 153 OperationObserver* observer, | 216 OperationObserver* observer, |
| 154 JobScheduler* scheduler, | 217 JobScheduler* scheduler, |
| 155 internal::ResourceMetadata* metadata, | 218 internal::ResourceMetadata* metadata, |
| 156 internal::FileCache* cache, | 219 internal::FileCache* cache, |
| 157 const ResourceIdCanonicalizer& id_canonicalizer) | 220 const ResourceIdCanonicalizer& id_canonicalizer) |
| 158 : blocking_task_runner_(blocking_task_runner), | 221 : blocking_task_runner_(blocking_task_runner), |
| 159 observer_(observer), | 222 observer_(observer), |
| 160 scheduler_(scheduler), | 223 scheduler_(scheduler), |
| 161 metadata_(metadata), | 224 metadata_(metadata), |
| (...skipping 12 matching lines...) Expand all Loading... |
| 174 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 237 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 175 } | 238 } |
| 176 | 239 |
| 177 void CopyOperation::Copy(const base::FilePath& src_file_path, | 240 void CopyOperation::Copy(const base::FilePath& src_file_path, |
| 178 const base::FilePath& dest_file_path, | 241 const base::FilePath& dest_file_path, |
| 179 bool preserve_last_modified, | 242 bool preserve_last_modified, |
| 180 const FileOperationCallback& callback) { | 243 const FileOperationCallback& callback) { |
| 181 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 244 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 182 DCHECK(!callback.is_null()); | 245 DCHECK(!callback.is_null()); |
| 183 | 246 |
| 184 CopyParams params; | 247 CopyParams* params = new CopyParams; |
| 185 params.dest_file_path = dest_file_path; | 248 params->src_file_path = src_file_path; |
| 186 params.preserve_last_modified = preserve_last_modified; | 249 params->dest_file_path = dest_file_path; |
| 187 params.callback = callback; | 250 params->preserve_last_modified = preserve_last_modified; |
| 251 params->callback = callback; |
| 188 | 252 |
| 189 ResourceEntry* src_entry = new ResourceEntry; | 253 std::vector<std::string>* updated_local_ids = new std::vector<std::string>; |
| 190 std::string* parent_resource_id = new std::string; | 254 bool* directory_changed = new bool(false); |
| 255 bool* should_copy_on_server = new bool(false); |
| 191 base::PostTaskAndReplyWithResult( | 256 base::PostTaskAndReplyWithResult( |
| 192 blocking_task_runner_.get(), | 257 blocking_task_runner_.get(), |
| 193 FROM_HERE, | 258 FROM_HERE, |
| 194 base::Bind(&PrepareCopy, | 259 base::Bind(&TryToCopyLocally, metadata_, cache_, params, |
| 195 metadata_, src_file_path, dest_file_path, | 260 updated_local_ids, directory_changed, should_copy_on_server), |
| 196 src_entry, parent_resource_id), | 261 base::Bind(&CopyOperation::CopyAfterTryToCopyLocally, |
| 197 base::Bind(&CopyOperation::CopyAfterPrepare, | 262 weak_ptr_factory_.GetWeakPtr(), base::Owned(params), |
| 198 weak_ptr_factory_.GetWeakPtr(), params, | 263 base::Owned(updated_local_ids), base::Owned(directory_changed), |
| 199 base::Owned(src_entry), base::Owned(parent_resource_id))); | 264 base::Owned(should_copy_on_server))); |
| 200 } | 265 } |
| 201 | 266 |
| 202 void CopyOperation::CopyAfterPrepare(const CopyParams& params, | 267 void CopyOperation::CopyAfterTryToCopyLocally( |
| 203 ResourceEntry* src_entry, | 268 const CopyParams* params, |
| 204 std::string* parent_resource_id, | 269 const std::vector<std::string>* updated_local_ids, |
| 205 FileError error) { | 270 const bool* directory_changed, |
| 271 const bool* should_copy_on_server, |
| 272 FileError error) { |
| 206 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 273 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 207 DCHECK(!params.callback.is_null()); | 274 DCHECK(!params->callback.is_null()); |
| 208 | 275 |
| 209 if (error != FILE_ERROR_OK) { | 276 for (size_t i = 0; i < updated_local_ids->size(); ++i) |
| 210 params.callback.Run(error); | 277 observer_->OnEntryUpdatedByOperation((*updated_local_ids)[i]); |
| 278 |
| 279 if (*directory_changed) |
| 280 observer_->OnDirectoryChangedByOperation(params->dest_file_path.DirName()); |
| 281 |
| 282 if (error != FILE_ERROR_OK || !*should_copy_on_server) { |
| 283 params->callback.Run(error); |
| 211 return; | 284 return; |
| 212 } | 285 } |
| 213 | 286 |
| 214 base::FilePath new_title = params.dest_file_path.BaseName(); | 287 base::FilePath new_title = params->dest_file_path.BaseName(); |
| 215 if (src_entry->file_specific_info().is_hosted_document()) { | 288 if (params->src_entry.file_specific_info().is_hosted_document()) { |
| 216 // Drop the document extension, which should not be in the title. | 289 // Drop the document extension, which should not be in the title. |
| 217 // TODO(yoshiki): Remove this code with crbug.com/223304. | 290 // TODO(yoshiki): Remove this code with crbug.com/223304. |
| 218 new_title = new_title.RemoveExtension(); | 291 new_title = new_title.RemoveExtension(); |
| 219 } | 292 } |
| 220 | 293 |
| 221 base::Time last_modified = | 294 base::Time last_modified = |
| 222 params.preserve_last_modified ? | 295 params->preserve_last_modified ? |
| 223 base::Time::FromInternalValue(src_entry->file_info().last_modified()) : | 296 base::Time::FromInternalValue( |
| 224 base::Time(); | 297 params->src_entry.file_info().last_modified()) : base::Time(); |
| 225 | 298 |
| 226 CopyResourceOnServer( | 299 CopyResourceOnServer( |
| 227 src_entry->resource_id(), *parent_resource_id, | 300 params->src_entry.resource_id(), params->parent_entry.resource_id(), |
| 228 new_title.AsUTF8Unsafe(), last_modified, params.callback); | 301 new_title.AsUTF8Unsafe(), last_modified, params->callback); |
| 229 } | 302 } |
| 230 | 303 |
| 231 void CopyOperation::TransferFileFromLocalToRemote( | 304 void CopyOperation::TransferFileFromLocalToRemote( |
| 232 const base::FilePath& local_src_path, | 305 const base::FilePath& local_src_path, |
| 233 const base::FilePath& remote_dest_path, | 306 const base::FilePath& remote_dest_path, |
| 234 const FileOperationCallback& callback) { | 307 const FileOperationCallback& callback) { |
| 235 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 308 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 236 DCHECK(!callback.is_null()); | 309 DCHECK(!callback.is_null()); |
| 237 | 310 |
| 238 std::string* gdoc_resource_id = new std::string; | 311 std::string* gdoc_resource_id = new std::string; |
| (...skipping 206 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 445 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 518 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 446 DCHECK(!callback.is_null()); | 519 DCHECK(!callback.is_null()); |
| 447 | 520 |
| 448 if (error == FILE_ERROR_OK) | 521 if (error == FILE_ERROR_OK) |
| 449 observer_->OnEntryUpdatedByOperation(*local_id); | 522 observer_->OnEntryUpdatedByOperation(*local_id); |
| 450 callback.Run(error); | 523 callback.Run(error); |
| 451 } | 524 } |
| 452 | 525 |
| 453 } // namespace file_system | 526 } // namespace file_system |
| 454 } // namespace drive | 527 } // namespace drive |
| OLD | NEW |