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 3 // found in the LICENSE file. 4 5 #include "chrome/browser/chromeos/drive/file_system.h" 6 7 #include "base/bind.h" 8 #include "base/files/file_util.h" 9 #include "base/prefs/pref_service.h" 10 #include "chrome/browser/chromeos/drive/change_list_loader.h" 11 #include "chrome/browser/chromeos/drive/directory_loader.h" 12 #include "chrome/browser/chromeos/drive/drive.pb.h" 13 #include "chrome/browser/chromeos/drive/file_cache.h" 14 #include "chrome/browser/chromeos/drive/file_change.h" 15 #include "chrome/browser/chromeos/drive/file_system/copy_operation.h" 16 #include "chrome/browser/chromeos/drive/file_system/create_directory_operation.h" 17 #include "chrome/browser/chromeos/drive/file_system/create_file_operation.h" 18 #include "chrome/browser/chromeos/drive/file_system/download_operation.h" 19 #include "chrome/browser/chromeos/drive/file_system/get_file_for_saving_operation.h" 20 #include "chrome/browser/chromeos/drive/file_system/move_operation.h" 21 #include "chrome/browser/chromeos/drive/file_system/open_file_operation.h" 22 #include "chrome/browser/chromeos/drive/file_system/remove_operation.h" 23 #include "chrome/browser/chromeos/drive/file_system/search_operation.h" 24 #include "chrome/browser/chromeos/drive/file_system/touch_operation.h" 25 #include "chrome/browser/chromeos/drive/file_system/truncate_operation.h" 26 #include "chrome/browser/chromeos/drive/file_system_observer.h" 27 #include "chrome/browser/chromeos/drive/file_system_util.h" 28 #include "chrome/browser/chromeos/drive/job_scheduler.h" 29 #include "chrome/browser/chromeos/drive/remove_stale_cache_files.h" 30 #include "chrome/browser/chromeos/drive/resource_entry_conversion.h" 31 #include "chrome/browser/chromeos/drive/search_metadata.h" 32 #include "chrome/browser/chromeos/drive/sync_client.h" 33 #include "chrome/browser/drive/drive_service_interface.h" 34 #include "chrome/common/pref_names.h" 35 #include "content/public/browser/browser_thread.h" 36 #include "google_apis/drive/drive_api_parser.h" 37 38 using content::BrowserThread; 39 40 namespace drive { 41 namespace { 42 43 // Gets a ResourceEntry from the metadata, and overwrites its file info when the 44 // cached file is dirty. 45 FileError GetLocallyStoredResourceEntry( 46 internal::ResourceMetadata* resource_metadata, 47 internal::FileCache* cache, 48 const base::FilePath& file_path, 49 ResourceEntry* entry) { 50 std::string local_id; 51 FileError error = resource_metadata->GetIdByPath(file_path, &local_id); 52 if (error != FILE_ERROR_OK) 53 return error; 54 55 error = resource_metadata->GetResourceEntryById(local_id, entry); 56 if (error != FILE_ERROR_OK) 57 return error; 58 59 // For entries that will never be cached, use the original resource entry 60 // as is. 61 if (!entry->has_file_specific_info() || 62 entry->file_specific_info().is_hosted_document()) 63 return FILE_ERROR_OK; 64 65 // When cache is not found, use the original resource entry as is. 66 if (!entry->file_specific_info().has_cache_state()) 67 return FILE_ERROR_OK; 68 69 // When cache is non-dirty and obsolete (old hash), use the original entry. 70 if (!entry->file_specific_info().cache_state().is_dirty() && 71 entry->file_specific_info().md5() != 72 entry->file_specific_info().cache_state().md5()) 73 return FILE_ERROR_OK; 74 75 // If there's a valid cache, obtain the file info from the cache file itself. 76 base::FilePath local_cache_path; 77 error = cache->GetFile(local_id, &local_cache_path); 78 if (error != FILE_ERROR_OK) 79 return error; 80 81 base::File::Info file_info; 82 if (!base::GetFileInfo(local_cache_path, &file_info)) 83 return FILE_ERROR_NOT_FOUND; 84 85 entry->mutable_file_info()->set_size(file_info.size); 86 return FILE_ERROR_OK; 87 } 88 89 // Runs the callback with parameters. 90 void RunGetResourceEntryCallback(const GetResourceEntryCallback& callback, 91 scoped_ptr<ResourceEntry> entry, 92 FileError error) { 93 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 94 DCHECK(!callback.is_null()); 95 96 if (error != FILE_ERROR_OK) 97 entry.reset(); 98 callback.Run(error, entry.Pass()); 99 } 100 101 // Used to implement Pin(). 102 FileError PinInternal(internal::ResourceMetadata* resource_metadata, 103 internal::FileCache* cache, 104 const base::FilePath& file_path, 105 std::string* local_id) { 106 FileError error = resource_metadata->GetIdByPath(file_path, local_id); 107 if (error != FILE_ERROR_OK) 108 return error; 109 110 ResourceEntry entry; 111 error = resource_metadata->GetResourceEntryById(*local_id, &entry); 112 if (error != FILE_ERROR_OK) 113 return error; 114 115 // TODO(hashimoto): Support pinning directories. crbug.com/127831 116 if (entry.file_info().is_directory()) 117 return FILE_ERROR_NOT_A_FILE; 118 119 return cache->Pin(*local_id); 120 } 121 122 // Used to implement Unpin(). 123 FileError UnpinInternal(internal::ResourceMetadata* resource_metadata, 124 internal::FileCache* cache, 125 const base::FilePath& file_path, 126 std::string* local_id) { 127 FileError error = resource_metadata->GetIdByPath(file_path, local_id); 128 if (error != FILE_ERROR_OK) 129 return error; 130 131 return cache->Unpin(*local_id); 132 } 133 134 // Used to implement MarkCacheFileAsMounted(). 135 FileError MarkCacheFileAsMountedInternal( 136 internal::ResourceMetadata* resource_metadata, 137 internal::FileCache* cache, 138 const base::FilePath& drive_file_path, 139 base::FilePath* cache_file_path) { 140 std::string local_id; 141 FileError error = resource_metadata->GetIdByPath(drive_file_path, &local_id); 142 if (error != FILE_ERROR_OK) 143 return error; 144 145 return cache->MarkAsMounted(local_id, cache_file_path); 146 } 147 148 // Runs the callback with arguments. 149 void RunMarkMountedCallback(const MarkMountedCallback& callback, 150 base::FilePath* cache_file_path, 151 FileError error) { 152 DCHECK(!callback.is_null()); 153 callback.Run(error, *cache_file_path); 154 } 155 156 // Callback for ResourceMetadata::GetLargestChangestamp. 157 // |callback| must not be null. 158 void OnGetLargestChangestamp( 159 FileSystemMetadata metadata, // Will be modified. 160 const GetFilesystemMetadataCallback& callback, 161 const int64* largest_changestamp, 162 FileError error) { 163 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 164 DCHECK(!callback.is_null()); 165 166 metadata.largest_changestamp = *largest_changestamp; 167 callback.Run(metadata); 168 } 169 170 // Thin adapter to map GetFileCallback to FileOperationCallback. 171 void GetFileCallbackToFileOperationCallbackAdapter( 172 const FileOperationCallback& callback, 173 FileError error, 174 const base::FilePath& unused_file_path, 175 scoped_ptr<ResourceEntry> unused_entry) { 176 callback.Run(error); 177 } 178 179 // Clears |resource_metadata| and |cache|. 180 FileError ResetOnBlockingPool(internal::ResourceMetadata* resource_metadata, 181 internal::FileCache* cache) { 182 FileError error = resource_metadata->Reset(); 183 if (error != FILE_ERROR_OK) 184 return error; 185 return cache->ClearAll() ? FILE_ERROR_OK : FILE_ERROR_FAILED; 186 } 187 188 // Part of GetPathFromResourceId(). 189 // Obtains |file_path| from |resource_id|. The function should be run on the 190 // blocking pool. 191 FileError GetPathFromResourceIdOnBlockingPool( 192 internal::ResourceMetadata* resource_metadata, 193 const std::string& resource_id, 194 base::FilePath* file_path) { 195 std::string local_id; 196 const FileError error = 197 resource_metadata->GetIdByResourceId(resource_id, &local_id); 198 if (error != FILE_ERROR_OK) 199 return error; 200 return resource_metadata->GetFilePath(local_id, file_path); 201 } 202 203 // Part of GetPathFromResourceId(). 204 // Called when GetPathFromResourceIdInBlockingPool is complete. 205 void GetPathFromResourceIdAfterGetPath(base::FilePath* file_path, 206 const GetFilePathCallback& callback, 207 FileError error) { 208 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 209 callback.Run(error, *file_path); 210 } 211 212 // Excludes hosted documents from the given entries. 213 // Used to implement ReadDirectory(). 214 void FilterHostedDocuments(const ReadDirectoryEntriesCallback& callback, 215 scoped_ptr<ResourceEntryVector> entries) { 216 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 217 DCHECK(!callback.is_null()); 218 219 if (entries) { 220 // TODO(kinaba): Stop handling hide_hosted_docs here. crbug.com/256520. 221 scoped_ptr<ResourceEntryVector> filtered(new ResourceEntryVector); 222 for (size_t i = 0; i < entries->size(); ++i) { 223 if (entries->at(i).file_specific_info().is_hosted_document()) { 224 continue; 225 } 226 filtered->push_back(entries->at(i)); 227 } 228 entries.swap(filtered); 229 } 230 callback.Run(entries.Pass()); 231 } 232 233 // Adapter for using FileOperationCallback as google_apis::EntryActionCallback. 234 void RunFileOperationCallbackAsEntryActionCallback( 235 const FileOperationCallback& callback, 236 google_apis::GDataErrorCode error) { 237 callback.Run(GDataToFileError(error)); 238 } 239 240 } // namespace 241 242 struct FileSystem::CreateDirectoryParams { 243 base::FilePath directory_path; 244 bool is_exclusive; 245 bool is_recursive; 246 FileOperationCallback callback; 247 }; 248 249 FileSystem::FileSystem( 250 PrefService* pref_service, 251 EventLogger* logger, 252 internal::FileCache* cache, 253 DriveServiceInterface* drive_service, 254 JobScheduler* scheduler, 255 internal::ResourceMetadata* resource_metadata, 256 base::SequencedTaskRunner* blocking_task_runner, 257 const base::FilePath& temporary_file_directory) 258 : pref_service_(pref_service), 259 logger_(logger), 260 cache_(cache), 261 drive_service_(drive_service), 262 scheduler_(scheduler), 263 resource_metadata_(resource_metadata), 264 last_update_check_error_(FILE_ERROR_OK), 265 blocking_task_runner_(blocking_task_runner), 266 temporary_file_directory_(temporary_file_directory), 267 weak_ptr_factory_(this) { 268 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 269 270 ResetComponents(); 271 } 272 273 FileSystem::~FileSystem() { 274 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 275 276 directory_loader_->RemoveObserver(this); 277 change_list_loader_->RemoveObserver(this); 278 } 279 280 void FileSystem::Reset(const FileOperationCallback& callback) { 281 // Discard the current loader and operation objects and renew them. This is to 282 // avoid that changes initiated before the metadata reset is applied after the 283 // reset, which may cause an inconsistent state. 284 // TODO(kinaba): callbacks held in the subcomponents are discarded. We might 285 // want to have a way to abort and flush callbacks in in-flight operations. 286 ResetComponents(); 287 288 base::PostTaskAndReplyWithResult( 289 blocking_task_runner_.get(), 290 FROM_HERE, 291 base::Bind(&ResetOnBlockingPool, resource_metadata_, cache_), 292 callback); 293 } 294 295 void FileSystem::ResetComponents() { 296 file_system::OperationDelegate* delegate = this; 297 298 about_resource_loader_.reset(new internal::AboutResourceLoader(scheduler_)); 299 loader_controller_.reset(new internal::LoaderController); 300 change_list_loader_.reset(new internal::ChangeListLoader( 301 logger_, 302 blocking_task_runner_.get(), 303 resource_metadata_, 304 scheduler_, 305 about_resource_loader_.get(), 306 loader_controller_.get())); 307 change_list_loader_->AddObserver(this); 308 directory_loader_.reset(new internal::DirectoryLoader( 309 logger_, 310 blocking_task_runner_.get(), 311 resource_metadata_, 312 scheduler_, 313 about_resource_loader_.get(), 314 loader_controller_.get())); 315 directory_loader_->AddObserver(this); 316 317 sync_client_.reset(new internal::SyncClient(blocking_task_runner_.get(), 318 delegate, 319 scheduler_, 320 resource_metadata_, 321 cache_, 322 loader_controller_.get(), 323 temporary_file_directory_)); 324 325 copy_operation_.reset( 326 new file_system::CopyOperation(blocking_task_runner_.get(), 327 delegate, 328 scheduler_, 329 resource_metadata_, 330 cache_)); 331 create_directory_operation_.reset(new file_system::CreateDirectoryOperation( 332 blocking_task_runner_.get(), delegate, resource_metadata_)); 333 create_file_operation_.reset( 334 new file_system::CreateFileOperation(blocking_task_runner_.get(), 335 delegate, 336 resource_metadata_)); 337 move_operation_.reset( 338 new file_system::MoveOperation(blocking_task_runner_.get(), 339 delegate, 340 resource_metadata_)); 341 open_file_operation_.reset( 342 new file_system::OpenFileOperation(blocking_task_runner_.get(), 343 delegate, 344 scheduler_, 345 resource_metadata_, 346 cache_, 347 temporary_file_directory_)); 348 remove_operation_.reset( 349 new file_system::RemoveOperation(blocking_task_runner_.get(), 350 delegate, 351 resource_metadata_, 352 cache_)); 353 touch_operation_.reset(new file_system::TouchOperation( 354 blocking_task_runner_.get(), delegate, resource_metadata_)); 355 truncate_operation_.reset( 356 new file_system::TruncateOperation(blocking_task_runner_.get(), 357 delegate, 358 scheduler_, 359 resource_metadata_, 360 cache_, 361 temporary_file_directory_)); 362 download_operation_.reset( 363 new file_system::DownloadOperation(blocking_task_runner_.get(), 364 delegate, 365 scheduler_, 366 resource_metadata_, 367 cache_, 368 temporary_file_directory_)); 369 search_operation_.reset(new file_system::SearchOperation( 370 blocking_task_runner_.get(), scheduler_, resource_metadata_, 371 loader_controller_.get())); 372 get_file_for_saving_operation_.reset( 373 new file_system::GetFileForSavingOperation(logger_, 374 blocking_task_runner_.get(), 375 delegate, 376 scheduler_, 377 resource_metadata_, 378 cache_, 379 temporary_file_directory_)); 380 } 381 382 void FileSystem::CheckForUpdates() { 383 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 384 DVLOG(1) << "CheckForUpdates"; 385 386 change_list_loader_->CheckForUpdates( 387 base::Bind(&FileSystem::OnUpdateChecked, weak_ptr_factory_.GetWeakPtr())); 388 } 389 390 void FileSystem::OnUpdateChecked(FileError error) { 391 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 392 DVLOG(1) << "CheckForUpdates finished: " << FileErrorToString(error); 393 last_update_check_time_ = base::Time::Now(); 394 last_update_check_error_ = error; 395 } 396 397 void FileSystem::AddObserver(FileSystemObserver* observer) { 398 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 399 observers_.AddObserver(observer); 400 } 401 402 void FileSystem::RemoveObserver(FileSystemObserver* observer) { 403 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 404 observers_.RemoveObserver(observer); 405 } 406 407 void FileSystem::TransferFileFromLocalToRemote( 408 const base::FilePath& local_src_file_path, 409 const base::FilePath& remote_dest_file_path, 410 const FileOperationCallback& callback) { 411 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 412 DCHECK(!callback.is_null()); 413 copy_operation_->TransferFileFromLocalToRemote(local_src_file_path, 414 remote_dest_file_path, 415 callback); 416 } 417 418 void FileSystem::Copy(const base::FilePath& src_file_path, 419 const base::FilePath& dest_file_path, 420 bool preserve_last_modified, 421 const FileOperationCallback& callback) { 422 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 423 DCHECK(!callback.is_null()); 424 copy_operation_->Copy( 425 src_file_path, dest_file_path, preserve_last_modified, callback); 426 } 427 428 void FileSystem::Move(const base::FilePath& src_file_path, 429 const base::FilePath& dest_file_path, 430 const FileOperationCallback& callback) { 431 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 432 DCHECK(!callback.is_null()); 433 move_operation_->Move(src_file_path, dest_file_path, callback); 434 } 435 436 void FileSystem::Remove(const base::FilePath& file_path, 437 bool is_recursive, 438 const FileOperationCallback& callback) { 439 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 440 DCHECK(!callback.is_null()); 441 remove_operation_->Remove(file_path, is_recursive, callback); 442 } 443 444 void FileSystem::CreateDirectory( 445 const base::FilePath& directory_path, 446 bool is_exclusive, 447 bool is_recursive, 448 const FileOperationCallback& callback) { 449 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 450 DCHECK(!callback.is_null()); 451 452 CreateDirectoryParams params; 453 params.directory_path = directory_path; 454 params.is_exclusive = is_exclusive; 455 params.is_recursive = is_recursive; 456 params.callback = callback; 457 458 // Ensure its parent directory is loaded to the local metadata. 459 ReadDirectory(directory_path.DirName(), 460 ReadDirectoryEntriesCallback(), 461 base::Bind(&FileSystem::CreateDirectoryAfterRead, 462 weak_ptr_factory_.GetWeakPtr(), params)); 463 } 464 465 void FileSystem::CreateDirectoryAfterRead(const CreateDirectoryParams& params, 466 FileError error) { 467 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 468 DCHECK(!params.callback.is_null()); 469 470 DVLOG_IF(1, error != FILE_ERROR_OK) << "ReadDirectory failed. " 471 << FileErrorToString(error); 472 473 create_directory_operation_->CreateDirectory( 474 params.directory_path, params.is_exclusive, params.is_recursive, 475 params.callback); 476 } 477 478 void FileSystem::CreateFile(const base::FilePath& file_path, 479 bool is_exclusive, 480 const std::string& mime_type, 481 const FileOperationCallback& callback) { 482 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 483 DCHECK(!callback.is_null()); 484 create_file_operation_->CreateFile( 485 file_path, is_exclusive, mime_type, callback); 486 } 487 488 void FileSystem::TouchFile(const base::FilePath& file_path, 489 const base::Time& last_access_time, 490 const base::Time& last_modified_time, 491 const FileOperationCallback& callback) { 492 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 493 DCHECK(!callback.is_null()); 494 touch_operation_->TouchFile( 495 file_path, last_access_time, last_modified_time, callback); 496 } 497 498 void FileSystem::TruncateFile(const base::FilePath& file_path, 499 int64 length, 500 const FileOperationCallback& callback) { 501 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 502 DCHECK(!callback.is_null()); 503 truncate_operation_->Truncate(file_path, length, callback); 504 } 505 506 void FileSystem::Pin(const base::FilePath& file_path, 507 const FileOperationCallback& callback) { 508 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 509 DCHECK(!callback.is_null()); 510 511 std::string* local_id = new std::string; 512 base::PostTaskAndReplyWithResult( 513 blocking_task_runner_.get(), 514 FROM_HERE, 515 base::Bind(&PinInternal, resource_metadata_, cache_, file_path, local_id), 516 base::Bind(&FileSystem::FinishPin, 517 weak_ptr_factory_.GetWeakPtr(), 518 callback, 519 base::Owned(local_id))); 520 } 521 522 void FileSystem::FinishPin(const FileOperationCallback& callback, 523 const std::string* local_id, 524 FileError error) { 525 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 526 DCHECK(!callback.is_null()); 527 528 if (error == FILE_ERROR_OK) 529 sync_client_->AddFetchTask(*local_id); 530 callback.Run(error); 531 } 532 533 void FileSystem::Unpin(const base::FilePath& file_path, 534 const FileOperationCallback& callback) { 535 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 536 DCHECK(!callback.is_null()); 537 538 std::string* local_id = new std::string; 539 base::PostTaskAndReplyWithResult( 540 blocking_task_runner_.get(), 541 FROM_HERE, 542 base::Bind( 543 &UnpinInternal, resource_metadata_, cache_, file_path, local_id), 544 base::Bind(&FileSystem::FinishUnpin, 545 weak_ptr_factory_.GetWeakPtr(), 546 callback, 547 base::Owned(local_id))); 548 } 549 550 void FileSystem::FinishUnpin(const FileOperationCallback& callback, 551 const std::string* local_id, 552 FileError error) { 553 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 554 DCHECK(!callback.is_null()); 555 556 if (error == FILE_ERROR_OK) 557 sync_client_->RemoveFetchTask(*local_id); 558 callback.Run(error); 559 } 560 561 void FileSystem::GetFile(const base::FilePath& file_path, 562 const GetFileCallback& callback) { 563 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 564 DCHECK(!callback.is_null()); 565 566 download_operation_->EnsureFileDownloadedByPath( 567 file_path, 568 ClientContext(USER_INITIATED), 569 GetFileContentInitializedCallback(), 570 google_apis::GetContentCallback(), 571 callback); 572 } 573 574 void FileSystem::GetFileForSaving(const base::FilePath& file_path, 575 const GetFileCallback& callback) { 576 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 577 DCHECK(!callback.is_null()); 578 579 get_file_for_saving_operation_->GetFileForSaving(file_path, callback); 580 } 581 582 base::Closure FileSystem::GetFileContent( 583 const base::FilePath& file_path, 584 const GetFileContentInitializedCallback& initialized_callback, 585 const google_apis::GetContentCallback& get_content_callback, 586 const FileOperationCallback& completion_callback) { 587 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 588 DCHECK(!initialized_callback.is_null()); 589 DCHECK(!get_content_callback.is_null()); 590 DCHECK(!completion_callback.is_null()); 591 592 return download_operation_->EnsureFileDownloadedByPath( 593 file_path, 594 ClientContext(USER_INITIATED), 595 initialized_callback, 596 get_content_callback, 597 base::Bind(&GetFileCallbackToFileOperationCallbackAdapter, 598 completion_callback)); 599 } 600 601 void FileSystem::GetResourceEntry( 602 const base::FilePath& file_path, 603 const GetResourceEntryCallback& callback) { 604 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 605 DCHECK(!callback.is_null()); 606 607 ReadDirectory(file_path.DirName(), 608 ReadDirectoryEntriesCallback(), 609 base::Bind(&FileSystem::GetResourceEntryAfterRead, 610 weak_ptr_factory_.GetWeakPtr(), 611 file_path, 612 callback)); 613 } 614 615 void FileSystem::GetResourceEntryAfterRead( 616 const base::FilePath& file_path, 617 const GetResourceEntryCallback& callback, 618 FileError error) { 619 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 620 DCHECK(!callback.is_null()); 621 622 DVLOG_IF(1, error != FILE_ERROR_OK) << "ReadDirectory failed. " 623 << FileErrorToString(error); 624 625 scoped_ptr<ResourceEntry> entry(new ResourceEntry); 626 ResourceEntry* entry_ptr = entry.get(); 627 base::PostTaskAndReplyWithResult( 628 blocking_task_runner_.get(), 629 FROM_HERE, 630 base::Bind(&GetLocallyStoredResourceEntry, 631 resource_metadata_, 632 cache_, 633 file_path, 634 entry_ptr), 635 base::Bind(&RunGetResourceEntryCallback, callback, base::Passed(&entry))); 636 } 637 638 void FileSystem::ReadDirectory( 639 const base::FilePath& directory_path, 640 const ReadDirectoryEntriesCallback& entries_callback_in, 641 const FileOperationCallback& completion_callback) { 642 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 643 DCHECK(!completion_callback.is_null()); 644 645 const bool hide_hosted_docs = 646 pref_service_->GetBoolean(prefs::kDisableDriveHostedFiles); 647 ReadDirectoryEntriesCallback entries_callback = entries_callback_in; 648 if (!entries_callback.is_null() && hide_hosted_docs) 649 entries_callback = base::Bind(&FilterHostedDocuments, entries_callback); 650 651 directory_loader_->ReadDirectory( 652 directory_path, entries_callback, completion_callback); 653 654 // Also start loading all of the user's contents. 655 change_list_loader_->LoadIfNeeded( 656 base::Bind(&util::EmptyFileOperationCallback)); 657 } 658 659 void FileSystem::GetAvailableSpace( 660 const GetAvailableSpaceCallback& callback) { 661 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 662 DCHECK(!callback.is_null()); 663 664 about_resource_loader_->GetAboutResource( 665 base::Bind(&FileSystem::OnGetAboutResource, 666 weak_ptr_factory_.GetWeakPtr(), 667 callback)); 668 } 669 670 void FileSystem::OnGetAboutResource( 671 const GetAvailableSpaceCallback& callback, 672 google_apis::GDataErrorCode status, 673 scoped_ptr<google_apis::AboutResource> about_resource) { 674 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 675 DCHECK(!callback.is_null()); 676 677 FileError error = GDataToFileError(status); 678 if (error != FILE_ERROR_OK) { 679 callback.Run(error, -1, -1); 680 return; 681 } 682 DCHECK(about_resource); 683 684 callback.Run(FILE_ERROR_OK, 685 about_resource->quota_bytes_total(), 686 about_resource->quota_bytes_used()); 687 } 688 689 void FileSystem::GetShareUrl(const base::FilePath& file_path, 690 const GURL& embed_origin, 691 const GetShareUrlCallback& callback) { 692 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 693 DCHECK(!callback.is_null()); 694 695 // Resolve the resource id. 696 ResourceEntry* entry = new ResourceEntry; 697 base::PostTaskAndReplyWithResult( 698 blocking_task_runner_.get(), 699 FROM_HERE, 700 base::Bind(&internal::ResourceMetadata::GetResourceEntryByPath, 701 base::Unretained(resource_metadata_), 702 file_path, 703 entry), 704 base::Bind(&FileSystem::GetShareUrlAfterGetResourceEntry, 705 weak_ptr_factory_.GetWeakPtr(), 706 file_path, 707 embed_origin, 708 callback, 709 base::Owned(entry))); 710 } 711 712 void FileSystem::GetShareUrlAfterGetResourceEntry( 713 const base::FilePath& file_path, 714 const GURL& embed_origin, 715 const GetShareUrlCallback& callback, 716 ResourceEntry* entry, 717 FileError error) { 718 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 719 DCHECK(!callback.is_null()); 720 721 if (error != FILE_ERROR_OK) { 722 callback.Run(error, GURL()); 723 return; 724 } 725 if (entry->resource_id().empty()) { 726 // This entry does not exist on the server. Just return. 727 callback.Run(FILE_ERROR_FAILED, GURL()); 728 return; 729 } 730 731 scheduler_->GetShareUrl( 732 entry->resource_id(), 733 embed_origin, 734 ClientContext(USER_INITIATED), 735 base::Bind(&FileSystem::OnGetResourceEntryForGetShareUrl, 736 weak_ptr_factory_.GetWeakPtr(), 737 callback)); 738 } 739 740 void FileSystem::OnGetResourceEntryForGetShareUrl( 741 const GetShareUrlCallback& callback, 742 google_apis::GDataErrorCode status, 743 const GURL& share_url) { 744 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 745 DCHECK(!callback.is_null()); 746 747 FileError error = GDataToFileError(status); 748 if (error != FILE_ERROR_OK) { 749 callback.Run(error, GURL()); 750 return; 751 } 752 753 if (share_url.is_empty()) { 754 callback.Run(FILE_ERROR_FAILED, GURL()); 755 return; 756 } 757 758 callback.Run(FILE_ERROR_OK, share_url); 759 } 760 761 void FileSystem::Search(const std::string& search_query, 762 const GURL& next_link, 763 const SearchCallback& callback) { 764 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 765 DCHECK(!callback.is_null()); 766 search_operation_->Search(search_query, next_link, callback); 767 } 768 769 void FileSystem::SearchMetadata(const std::string& query, 770 int options, 771 int at_most_num_matches, 772 const SearchMetadataCallback& callback) { 773 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 774 775 // TODO(satorux): Stop handling hide_hosted_docs here. crbug.com/256520. 776 if (pref_service_->GetBoolean(prefs::kDisableDriveHostedFiles)) 777 options |= SEARCH_METADATA_EXCLUDE_HOSTED_DOCUMENTS; 778 779 drive::internal::SearchMetadata(blocking_task_runner_, 780 resource_metadata_, 781 query, 782 options, 783 at_most_num_matches, 784 callback); 785 } 786 787 void FileSystem::OnFileChangedByOperation(const FileChange& changed_files) { 788 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 789 790 FOR_EACH_OBSERVER( 791 FileSystemObserver, observers_, OnFileChanged(changed_files)); 792 } 793 794 void FileSystem::OnEntryUpdatedByOperation(const std::string& local_id) { 795 sync_client_->AddUpdateTask(ClientContext(USER_INITIATED), local_id); 796 } 797 798 void FileSystem::OnDriveSyncError(file_system::DriveSyncErrorType type, 799 const std::string& local_id) { 800 base::FilePath* file_path = new base::FilePath; 801 base::PostTaskAndReplyWithResult( 802 blocking_task_runner_.get(), 803 FROM_HERE, 804 base::Bind(&internal::ResourceMetadata::GetFilePath, 805 base::Unretained(resource_metadata_), 806 local_id, 807 file_path), 808 base::Bind(&FileSystem::OnDriveSyncErrorAfterGetFilePath, 809 weak_ptr_factory_.GetWeakPtr(), 810 type, 811 base::Owned(file_path))); 812 } 813 814 void FileSystem::OnDriveSyncErrorAfterGetFilePath( 815 file_system::DriveSyncErrorType type, 816 const base::FilePath* file_path, 817 FileError error) { 818 if (error != FILE_ERROR_OK) 819 return; 820 FOR_EACH_OBSERVER(FileSystemObserver, 821 observers_, 822 OnDriveSyncError(type, *file_path)); 823 } 824 825 bool FileSystem::WaitForSyncComplete(const std::string& local_id, 826 const FileOperationCallback& callback) { 827 return sync_client_->WaitForUpdateTaskToComplete(local_id, callback); 828 } 829 830 void FileSystem::OnDirectoryReloaded(const base::FilePath& directory_path) { 831 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 832 833 FOR_EACH_OBSERVER( 834 FileSystemObserver, observers_, OnDirectoryChanged(directory_path)); 835 } 836 837 void FileSystem::OnFileChanged(const FileChange& changed_files) { 838 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 839 840 FOR_EACH_OBSERVER( 841 FileSystemObserver, observers_, OnFileChanged(changed_files)); 842 } 843 844 void FileSystem::OnLoadFromServerComplete() { 845 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 846 847 sync_client_->StartCheckingExistingPinnedFiles(); 848 } 849 850 void FileSystem::OnInitialLoadComplete() { 851 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 852 853 blocking_task_runner_->PostTask(FROM_HERE, 854 base::Bind(&internal::RemoveStaleCacheFiles, 855 cache_, 856 resource_metadata_)); 857 sync_client_->StartProcessingBacklog(); 858 } 859 860 void FileSystem::GetMetadata( 861 const GetFilesystemMetadataCallback& callback) { 862 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 863 DCHECK(!callback.is_null()); 864 865 FileSystemMetadata metadata; 866 metadata.refreshing = change_list_loader_->IsRefreshing(); 867 868 // Metadata related to delta update. 869 metadata.last_update_check_time = last_update_check_time_; 870 metadata.last_update_check_error = last_update_check_error_; 871 872 int64* largest_changestamp = new int64(0); 873 base::PostTaskAndReplyWithResult( 874 blocking_task_runner_.get(), 875 FROM_HERE, 876 base::Bind(&internal::ResourceMetadata::GetLargestChangestamp, 877 base::Unretained(resource_metadata_), 878 largest_changestamp), 879 base::Bind(&OnGetLargestChangestamp, 880 metadata, 881 callback, 882 base::Owned(largest_changestamp))); 883 } 884 885 void FileSystem::MarkCacheFileAsMounted( 886 const base::FilePath& drive_file_path, 887 const MarkMountedCallback& callback) { 888 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 889 DCHECK(!callback.is_null()); 890 891 base::FilePath* cache_file_path = new base::FilePath; 892 base::PostTaskAndReplyWithResult( 893 blocking_task_runner_.get(), 894 FROM_HERE, 895 base::Bind(&MarkCacheFileAsMountedInternal, 896 resource_metadata_, 897 cache_, 898 drive_file_path, 899 cache_file_path), 900 base::Bind( 901 &RunMarkMountedCallback, callback, base::Owned(cache_file_path))); 902 } 903 904 void FileSystem::MarkCacheFileAsUnmounted( 905 const base::FilePath& cache_file_path, 906 const FileOperationCallback& callback) { 907 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 908 DCHECK(!callback.is_null()); 909 910 if (!cache_->IsUnderFileCacheDirectory(cache_file_path)) { 911 callback.Run(FILE_ERROR_FAILED); 912 return; 913 } 914 915 base::PostTaskAndReplyWithResult( 916 blocking_task_runner_.get(), 917 FROM_HERE, 918 base::Bind(&internal::FileCache::MarkAsUnmounted, 919 base::Unretained(cache_), 920 cache_file_path), 921 callback); 922 } 923 924 void FileSystem::AddPermission(const base::FilePath& drive_file_path, 925 const std::string& email, 926 google_apis::drive::PermissionRole role, 927 const FileOperationCallback& callback) { 928 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 929 DCHECK(!callback.is_null()); 930 931 // Resolve the resource id. 932 ResourceEntry* const entry = new ResourceEntry; 933 base::PostTaskAndReplyWithResult( 934 blocking_task_runner_.get(), 935 FROM_HERE, 936 base::Bind(&internal::ResourceMetadata::GetResourceEntryByPath, 937 base::Unretained(resource_metadata_), 938 drive_file_path, 939 entry), 940 base::Bind(&FileSystem::AddPermissionAfterGetResourceEntry, 941 weak_ptr_factory_.GetWeakPtr(), 942 email, 943 role, 944 callback, 945 base::Owned(entry))); 946 } 947 948 void FileSystem::AddPermissionAfterGetResourceEntry( 949 const std::string& email, 950 google_apis::drive::PermissionRole role, 951 const FileOperationCallback& callback, 952 ResourceEntry* entry, 953 FileError error) { 954 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 955 956 if (error != FILE_ERROR_OK) { 957 callback.Run(error); 958 return; 959 } 960 961 scheduler_->AddPermission( 962 entry->resource_id(), 963 email, 964 role, 965 base::Bind(&RunFileOperationCallbackAsEntryActionCallback, callback)); 966 } 967 968 void FileSystem::OpenFile(const base::FilePath& file_path, 969 OpenMode open_mode, 970 const std::string& mime_type, 971 const OpenFileCallback& callback) { 972 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 973 DCHECK(!callback.is_null()); 974 975 open_file_operation_->OpenFile(file_path, open_mode, mime_type, callback); 976 } 977 978 void FileSystem::GetPathFromResourceId(const std::string& resource_id, 979 const GetFilePathCallback& callback) { 980 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 981 DCHECK(!callback.is_null()); 982 983 base::FilePath* const file_path = new base::FilePath(); 984 base::PostTaskAndReplyWithResult( 985 blocking_task_runner_.get(), 986 FROM_HERE, 987 base::Bind(&GetPathFromResourceIdOnBlockingPool, 988 resource_metadata_, 989 resource_id, 990 file_path), 991 base::Bind(&GetPathFromResourceIdAfterGetPath, 992 base::Owned(file_path), 993 callback)); 994 } 995 } // namespace drive 996