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/file_util.h" 9 #include "base/message_loop/message_loop_proxy.h" 10 #include "base/platform_file.h" 11 #include "base/prefs/pref_change_registrar.h" 12 #include "base/prefs/pref_service.h" 13 #include "base/strings/stringprintf.h" 14 #include "base/threading/sequenced_worker_pool.h" 15 #include "chrome/browser/browser_process.h" 16 #include "chrome/browser/chromeos/drive/change_list_loader.h" 17 #include "chrome/browser/chromeos/drive/change_list_processor.h" 18 #include "chrome/browser/chromeos/drive/drive.pb.h" 19 #include "chrome/browser/chromeos/drive/file_cache.h" 20 #include "chrome/browser/chromeos/drive/file_system/copy_operation.h" 21 #include "chrome/browser/chromeos/drive/file_system/create_directory_operation.h" 22 #include "chrome/browser/chromeos/drive/file_system/create_file_operation.h" 23 #include "chrome/browser/chromeos/drive/file_system/download_operation.h" 24 #include "chrome/browser/chromeos/drive/file_system/get_file_for_saving_operation.h" 25 #include "chrome/browser/chromeos/drive/file_system/move_operation.h" 26 #include "chrome/browser/chromeos/drive/file_system/open_file_operation.h" 27 #include "chrome/browser/chromeos/drive/file_system/remove_operation.h" 28 #include "chrome/browser/chromeos/drive/file_system/search_operation.h" 29 #include "chrome/browser/chromeos/drive/file_system/touch_operation.h" 30 #include "chrome/browser/chromeos/drive/file_system/truncate_operation.h" 31 #include "chrome/browser/chromeos/drive/file_system/update_operation.h" 32 #include "chrome/browser/chromeos/drive/file_system_observer.h" 33 #include "chrome/browser/chromeos/drive/file_system_util.h" 34 #include "chrome/browser/chromeos/drive/job_scheduler.h" 35 #include "chrome/browser/chromeos/drive/logging.h" 36 #include "chrome/browser/chromeos/drive/remove_stale_cache_files.h" 37 #include "chrome/browser/chromeos/drive/resource_entry_conversion.h" 38 #include "chrome/browser/chromeos/drive/search_metadata.h" 39 #include "chrome/browser/chromeos/drive/sync_client.h" 40 #include "chrome/browser/drive/drive_api_util.h" 41 #include "chrome/browser/drive/drive_service_interface.h" 42 #include "chrome/browser/google_apis/drive_api_parser.h" 43 #include "chrome/common/pref_names.h" 44 #include "content/public/browser/browser_thread.h" 45 #include "net/http/http_status_code.h" 46 47 using content::BrowserThread; 48 49 namespace drive { 50 namespace { 51 52 // Gets a ResourceEntry from the metadata, and overwrites its file info when the 53 // cached file is dirty. 54 FileError GetLocallyStoredResourceEntry( 55 internal::ResourceMetadata* resource_metadata, 56 internal::FileCache* cache, 57 const base::FilePath& file_path, 58 ResourceEntry* entry) { 59 FileError error = 60 resource_metadata->GetResourceEntryByPath(file_path, entry); 61 if (error != FILE_ERROR_OK) 62 return error; 63 64 // For entries that will never be cached, use the original resource entry 65 // as is. 66 if (!entry->has_file_specific_info() || 67 entry->file_specific_info().is_hosted_document()) 68 return FILE_ERROR_OK; 69 70 // When no dirty cache is found, use the original resource entry as is. 71 FileCacheEntry cache_entry; 72 if (!cache->GetCacheEntry(entry->resource_id(), &cache_entry) || 73 !cache_entry.is_dirty()) 74 return FILE_ERROR_OK; 75 76 // If the cache is dirty, obtain the file info from the cache file itself. 77 base::FilePath local_cache_path; 78 error = cache->GetFile(entry->resource_id(), &local_cache_path); 79 if (error != FILE_ERROR_OK) 80 return error; 81 82 base::PlatformFileInfo file_info; 83 if (!file_util::GetFileInfo(local_cache_path, &file_info)) 84 return FILE_ERROR_NOT_FOUND; 85 86 SetPlatformFileInfoToResourceEntry(file_info, entry); 87 return FILE_ERROR_OK; 88 } 89 90 // Runs the callback with parameters. 91 void RunGetResourceEntryCallback(const GetResourceEntryCallback& callback, 92 scoped_ptr<ResourceEntry> entry, 93 FileError error) { 94 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 95 DCHECK(!callback.is_null()); 96 97 if (error != FILE_ERROR_OK) 98 entry.reset(); 99 callback.Run(error, entry.Pass()); 100 } 101 102 // Callback for ResourceMetadata::GetLargestChangestamp. 103 // |callback| must not be null. 104 void OnGetLargestChangestamp( 105 FileSystemMetadata metadata, // Will be modified. 106 const GetFilesystemMetadataCallback& callback, 107 int64 largest_changestamp) { 108 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 109 DCHECK(!callback.is_null()); 110 111 metadata.largest_changestamp = largest_changestamp; 112 callback.Run(metadata); 113 } 114 115 // Thin adapter to map GetFileCallback to FileOperationCallback. 116 void GetFileCallbackToFileOperationCallbackAdapter( 117 const FileOperationCallback& callback, 118 FileError error, 119 const base::FilePath& unused_file_path, 120 scoped_ptr<ResourceEntry> unused_entry) { 121 callback.Run(error); 122 } 123 124 // Checks whether the |url| passed to the constructor is accessible. If it is 125 // not, invokes |on_stale_closure|. 126 class StaleURLChecker : public net::URLFetcherDelegate { 127 public: 128 StaleURLChecker(const GURL& url, const base::Closure& on_stale_closure) 129 : on_stale_closure_(on_stale_closure) { 130 fetcher_.reset(net::URLFetcher::Create(url, net::URLFetcher::HEAD, this)); 131 fetcher_->SetRequestContext(g_browser_process->system_request_context()); 132 fetcher_->Start(); 133 } 134 135 virtual void OnURLFetchComplete(const net::URLFetcher* source) OVERRIDE { 136 int code = source->GetResponseCode(); 137 if (code == net::HTTP_FORBIDDEN) 138 on_stale_closure_.Run(); 139 delete this; 140 } 141 142 private: 143 scoped_ptr<net::URLFetcher> fetcher_; 144 const base::Closure on_stale_closure_; 145 }; 146 147 // Checks the first thumbnail URL in |entries| whether it is still available 148 // by sending a HEAD request. If it's stale, invokes |on_stale_closure|. 149 void CheckStaleThumbnailURL(ResourceEntryVector* entries, 150 const base::Closure& on_stale_closure) { 151 const char kImageThumbnailDomain[] = "googleusercontent.com"; 152 for (size_t i = 0; i < entries->size(); ++i) { 153 const std::string& url = 154 entries->at(i).file_specific_info().thumbnail_url(); 155 if (url.find(kImageThumbnailDomain) != std::string::npos) { 156 // The stale URL checker deletes itself. 157 new StaleURLChecker(GURL(url), on_stale_closure); 158 break; 159 } 160 } 161 } 162 163 } // namespace 164 165 FileSystem::FileSystem( 166 PrefService* pref_service, 167 internal::FileCache* cache, 168 DriveServiceInterface* drive_service, 169 JobScheduler* scheduler, 170 internal::ResourceMetadata* resource_metadata, 171 base::SequencedTaskRunner* blocking_task_runner, 172 const base::FilePath& temporary_file_directory) 173 : pref_service_(pref_service), 174 cache_(cache), 175 drive_service_(drive_service), 176 scheduler_(scheduler), 177 resource_metadata_(resource_metadata), 178 last_update_check_error_(FILE_ERROR_OK), 179 hide_hosted_docs_(false), 180 blocking_task_runner_(blocking_task_runner), 181 temporary_file_directory_(temporary_file_directory), 182 weak_ptr_factory_(this) { 183 // Should be created from the file browser extension API on UI thread. 184 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 185 } 186 187 void FileSystem::Reload() { 188 resource_metadata_->ResetOnUIThread(base::Bind( 189 &FileSystem::ReloadAfterReset, 190 weak_ptr_factory_.GetWeakPtr())); 191 } 192 193 void FileSystem::Initialize() { 194 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 195 196 SetupChangeListLoader(); 197 198 file_system::OperationObserver* observer = this; 199 copy_operation_.reset( 200 new file_system::CopyOperation(blocking_task_runner_.get(), 201 observer, 202 scheduler_, 203 resource_metadata_, 204 cache_, 205 drive_service_, 206 temporary_file_directory_)); 207 create_directory_operation_.reset(new file_system::CreateDirectoryOperation( 208 blocking_task_runner_.get(), observer, scheduler_, resource_metadata_)); 209 create_file_operation_.reset( 210 new file_system::CreateFileOperation(blocking_task_runner_.get(), 211 observer, 212 scheduler_, 213 resource_metadata_, 214 cache_)); 215 move_operation_.reset( 216 new file_system::MoveOperation(observer, scheduler_, resource_metadata_)); 217 open_file_operation_.reset( 218 new file_system::OpenFileOperation(blocking_task_runner_.get(), 219 observer, 220 scheduler_, 221 resource_metadata_, 222 cache_, 223 temporary_file_directory_)); 224 remove_operation_.reset( 225 new file_system::RemoveOperation(blocking_task_runner_.get(), 226 observer, 227 scheduler_, 228 resource_metadata_, 229 cache_)); 230 touch_operation_.reset(new file_system::TouchOperation( 231 blocking_task_runner_.get(), observer, scheduler_, resource_metadata_)); 232 truncate_operation_.reset( 233 new file_system::TruncateOperation(blocking_task_runner_.get(), 234 observer, 235 scheduler_, 236 resource_metadata_, 237 cache_, 238 temporary_file_directory_)); 239 download_operation_.reset( 240 new file_system::DownloadOperation(blocking_task_runner_.get(), 241 observer, 242 scheduler_, 243 resource_metadata_, 244 cache_, 245 temporary_file_directory_)); 246 update_operation_.reset( 247 new file_system::UpdateOperation(blocking_task_runner_.get(), 248 observer, 249 scheduler_, 250 resource_metadata_, 251 cache_)); 252 search_operation_.reset(new file_system::SearchOperation( 253 blocking_task_runner_.get(), scheduler_, resource_metadata_)); 254 get_file_for_saving_operation_.reset( 255 new file_system::GetFileForSavingOperation(blocking_task_runner_.get(), 256 observer, 257 scheduler_, 258 resource_metadata_, 259 cache_, 260 temporary_file_directory_)); 261 262 sync_client_.reset(new internal::SyncClient(blocking_task_runner_.get(), 263 observer, 264 scheduler_, 265 resource_metadata_, 266 cache_, 267 temporary_file_directory_)); 268 hide_hosted_docs_ = 269 pref_service_->GetBoolean(prefs::kDisableDriveHostedFiles); 270 271 InitializePreferenceObserver(); 272 } 273 274 void FileSystem::ReloadAfterReset(FileError error) { 275 if (error != FILE_ERROR_OK) { 276 LOG(ERROR) << "Failed to reset the resource metadata: " 277 << FileErrorToString(error); 278 return; 279 } 280 281 SetupChangeListLoader(); 282 283 change_list_loader_->LoadIfNeeded( 284 DirectoryFetchInfo(), 285 base::Bind(&FileSystem::OnUpdateChecked, 286 weak_ptr_factory_.GetWeakPtr())); 287 } 288 289 void FileSystem::SetupChangeListLoader() { 290 change_list_loader_.reset(new internal::ChangeListLoader( 291 blocking_task_runner_.get(), resource_metadata_, scheduler_)); 292 change_list_loader_->AddObserver(this); 293 } 294 295 void FileSystem::CheckForUpdates() { 296 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 297 DVLOG(1) << "CheckForUpdates"; 298 299 if (change_list_loader_) { 300 change_list_loader_->CheckForUpdates( 301 base::Bind(&FileSystem::OnUpdateChecked, 302 weak_ptr_factory_.GetWeakPtr())); 303 } 304 } 305 306 void FileSystem::OnUpdateChecked(FileError error) { 307 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 308 DVLOG(1) << "CheckForUpdates finished: " << FileErrorToString(error); 309 last_update_check_time_ = base::Time::Now(); 310 last_update_check_error_ = error; 311 } 312 313 FileSystem::~FileSystem() { 314 // This should be called from UI thread, from DriveIntegrationService 315 // shutdown. 316 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 317 318 change_list_loader_->RemoveObserver(this); 319 } 320 321 void FileSystem::AddObserver(FileSystemObserver* observer) { 322 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 323 observers_.AddObserver(observer); 324 } 325 326 void FileSystem::RemoveObserver(FileSystemObserver* observer) { 327 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 328 observers_.RemoveObserver(observer); 329 } 330 331 void FileSystem::TransferFileFromRemoteToLocal( 332 const base::FilePath& remote_src_file_path, 333 const base::FilePath& local_dest_file_path, 334 const FileOperationCallback& callback) { 335 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 336 DCHECK(!callback.is_null()); 337 copy_operation_->TransferFileFromRemoteToLocal(remote_src_file_path, 338 local_dest_file_path, 339 callback); 340 } 341 342 void FileSystem::TransferFileFromLocalToRemote( 343 const base::FilePath& local_src_file_path, 344 const base::FilePath& remote_dest_file_path, 345 const FileOperationCallback& callback) { 346 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 347 DCHECK(!callback.is_null()); 348 copy_operation_->TransferFileFromLocalToRemote(local_src_file_path, 349 remote_dest_file_path, 350 callback); 351 } 352 353 void FileSystem::Copy(const base::FilePath& src_file_path, 354 const base::FilePath& dest_file_path, 355 const FileOperationCallback& callback) { 356 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 357 DCHECK(!callback.is_null()); 358 copy_operation_->Copy(src_file_path, dest_file_path, callback); 359 } 360 361 void FileSystem::Move(const base::FilePath& src_file_path, 362 const base::FilePath& dest_file_path, 363 const FileOperationCallback& callback) { 364 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 365 DCHECK(!callback.is_null()); 366 move_operation_->Move(src_file_path, dest_file_path, callback); 367 } 368 369 void FileSystem::Remove(const base::FilePath& file_path, 370 bool is_recursive, 371 const FileOperationCallback& callback) { 372 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 373 DCHECK(!callback.is_null()); 374 remove_operation_->Remove(file_path, is_recursive, callback); 375 } 376 377 void FileSystem::CreateDirectory( 378 const base::FilePath& directory_path, 379 bool is_exclusive, 380 bool is_recursive, 381 const FileOperationCallback& callback) { 382 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 383 DCHECK(!callback.is_null()); 384 385 change_list_loader_->LoadIfNeeded( 386 DirectoryFetchInfo(), 387 base::Bind(&FileSystem::CreateDirectoryAfterLoad, 388 weak_ptr_factory_.GetWeakPtr(), 389 directory_path, is_exclusive, is_recursive, callback)); 390 } 391 392 void FileSystem::CreateDirectoryAfterLoad( 393 const base::FilePath& directory_path, 394 bool is_exclusive, 395 bool is_recursive, 396 const FileOperationCallback& callback, 397 FileError load_error) { 398 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 399 DCHECK(!callback.is_null()); 400 401 if (load_error != FILE_ERROR_OK) { 402 callback.Run(load_error); 403 return; 404 } 405 406 create_directory_operation_->CreateDirectory( 407 directory_path, is_exclusive, is_recursive, callback); 408 } 409 410 void FileSystem::CreateFile(const base::FilePath& file_path, 411 bool is_exclusive, 412 const FileOperationCallback& callback) { 413 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 414 DCHECK(!callback.is_null()); 415 create_file_operation_->CreateFile(file_path, is_exclusive, callback); 416 } 417 418 void FileSystem::TouchFile(const base::FilePath& file_path, 419 const base::Time& last_access_time, 420 const base::Time& last_modified_time, 421 const FileOperationCallback& callback) { 422 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 423 DCHECK(!last_access_time.is_null()); 424 DCHECK(!last_modified_time.is_null()); 425 DCHECK(!callback.is_null()); 426 touch_operation_->TouchFile( 427 file_path, last_access_time, last_modified_time, callback); 428 } 429 430 void FileSystem::TruncateFile(const base::FilePath& file_path, 431 int64 length, 432 const FileOperationCallback& callback) { 433 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 434 DCHECK(!callback.is_null()); 435 truncate_operation_->Truncate(file_path, length, callback); 436 } 437 438 void FileSystem::Pin(const base::FilePath& file_path, 439 const FileOperationCallback& callback) { 440 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 441 DCHECK(!callback.is_null()); 442 443 GetResourceEntryByPath(file_path, 444 base::Bind(&FileSystem::PinAfterGetResourceEntryByPath, 445 weak_ptr_factory_.GetWeakPtr(), 446 callback)); 447 } 448 449 void FileSystem::PinAfterGetResourceEntryByPath( 450 const FileOperationCallback& callback, 451 FileError error, 452 scoped_ptr<ResourceEntry> entry) { 453 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 454 DCHECK(!callback.is_null()); 455 456 // TODO(hashimoto): Support pinning directories. crbug.com/127831 457 if (entry && entry->file_info().is_directory()) 458 error = FILE_ERROR_NOT_A_FILE; 459 460 if (error != FILE_ERROR_OK) { 461 callback.Run(error); 462 return; 463 } 464 DCHECK(entry); 465 466 cache_->PinOnUIThread(entry->resource_id(), 467 base::Bind(&FileSystem::FinishPin, 468 weak_ptr_factory_.GetWeakPtr(), 469 callback, 470 entry->resource_id())); 471 } 472 473 void FileSystem::FinishPin(const FileOperationCallback& callback, 474 const std::string& resource_id, 475 FileError error) { 476 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 477 DCHECK(!callback.is_null()); 478 479 if (error == FILE_ERROR_OK) 480 sync_client_->AddFetchTask(resource_id); 481 callback.Run(error); 482 } 483 484 void FileSystem::Unpin(const base::FilePath& file_path, 485 const FileOperationCallback& callback) { 486 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 487 DCHECK(!callback.is_null()); 488 489 GetResourceEntryByPath( 490 file_path, 491 base::Bind(&FileSystem::UnpinAfterGetResourceEntryByPath, 492 weak_ptr_factory_.GetWeakPtr(), 493 callback)); 494 } 495 496 void FileSystem::UnpinAfterGetResourceEntryByPath( 497 const FileOperationCallback& callback, 498 FileError error, 499 scoped_ptr<ResourceEntry> entry) { 500 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 501 DCHECK(!callback.is_null()); 502 503 // TODO(hashimoto): Support pinning directories. crbug.com/127831 504 if (entry && entry->file_info().is_directory()) 505 error = FILE_ERROR_NOT_A_FILE; 506 507 if (error != FILE_ERROR_OK) { 508 callback.Run(error); 509 return; 510 } 511 DCHECK(entry); 512 513 cache_->UnpinOnUIThread(entry->resource_id(), 514 base::Bind(&FileSystem::FinishUnpin, 515 weak_ptr_factory_.GetWeakPtr(), 516 callback, 517 entry->resource_id())); 518 } 519 520 void FileSystem::FinishUnpin(const FileOperationCallback& callback, 521 const std::string& resource_id, 522 FileError error) { 523 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 524 DCHECK(!callback.is_null()); 525 526 if (error == FILE_ERROR_OK) 527 sync_client_->RemoveFetchTask(resource_id); 528 callback.Run(error); 529 } 530 531 void FileSystem::GetFileByPath(const base::FilePath& file_path, 532 const GetFileCallback& callback) { 533 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 534 DCHECK(!callback.is_null()); 535 536 download_operation_->EnsureFileDownloadedByPath( 537 file_path, 538 ClientContext(USER_INITIATED), 539 GetFileContentInitializedCallback(), 540 google_apis::GetContentCallback(), 541 callback); 542 } 543 544 void FileSystem::GetFileByPathForSaving(const base::FilePath& file_path, 545 const GetFileCallback& callback) { 546 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 547 DCHECK(!callback.is_null()); 548 549 get_file_for_saving_operation_->GetFileForSaving(file_path, callback); 550 } 551 552 void FileSystem::GetFileContentByPath( 553 const base::FilePath& file_path, 554 const GetFileContentInitializedCallback& initialized_callback, 555 const google_apis::GetContentCallback& get_content_callback, 556 const FileOperationCallback& completion_callback) { 557 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 558 DCHECK(!initialized_callback.is_null()); 559 DCHECK(!get_content_callback.is_null()); 560 DCHECK(!completion_callback.is_null()); 561 562 download_operation_->EnsureFileDownloadedByPath( 563 file_path, 564 ClientContext(USER_INITIATED), 565 initialized_callback, 566 get_content_callback, 567 base::Bind(&GetFileCallbackToFileOperationCallbackAdapter, 568 completion_callback)); 569 } 570 571 void FileSystem::GetResourceEntryByPath( 572 const base::FilePath& file_path, 573 const GetResourceEntryCallback& callback) { 574 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 575 DCHECK(!callback.is_null()); 576 577 scoped_ptr<ResourceEntry> entry(new ResourceEntry); 578 ResourceEntry* entry_ptr = entry.get(); 579 base::PostTaskAndReplyWithResult( 580 blocking_task_runner_, 581 FROM_HERE, 582 base::Bind(&GetLocallyStoredResourceEntry, 583 resource_metadata_, 584 cache_, 585 file_path, 586 entry_ptr), 587 base::Bind(&FileSystem::GetResourceEntryByPathAfterGetEntry, 588 weak_ptr_factory_.GetWeakPtr(), 589 file_path, 590 callback, 591 base::Passed(&entry))); 592 } 593 594 void FileSystem::GetResourceEntryByPathAfterGetEntry( 595 const base::FilePath& file_path, 596 const GetResourceEntryCallback& callback, 597 scoped_ptr<ResourceEntry> entry, 598 FileError error) { 599 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 600 DCHECK(!callback.is_null()); 601 602 if (error == FILE_ERROR_OK) { 603 callback.Run(error, entry.Pass()); 604 return; 605 } 606 607 // If the information about the path is not in the local ResourceMetadata, 608 // try fetching information of the directory and retry. 609 LoadDirectoryIfNeeded( 610 file_path.DirName(), 611 base::Bind(&FileSystem::GetResourceEntryByPathAfterLoad, 612 weak_ptr_factory_.GetWeakPtr(), 613 file_path, 614 callback)); 615 } 616 617 void FileSystem::GetResourceEntryByPathAfterLoad( 618 const base::FilePath& file_path, 619 const GetResourceEntryCallback& callback, 620 FileError error) { 621 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 622 DCHECK(!callback.is_null()); 623 624 if (error != FILE_ERROR_OK) { 625 callback.Run(error, scoped_ptr<ResourceEntry>()); 626 return; 627 } 628 629 scoped_ptr<ResourceEntry> entry(new ResourceEntry); 630 ResourceEntry* entry_ptr = entry.get(); 631 base::PostTaskAndReplyWithResult( 632 blocking_task_runner_, 633 FROM_HERE, 634 base::Bind(&GetLocallyStoredResourceEntry, 635 resource_metadata_, 636 cache_, 637 file_path, 638 entry_ptr), 639 base::Bind(&RunGetResourceEntryCallback, 640 callback, 641 base::Passed(&entry))); 642 } 643 644 void FileSystem::ReadDirectoryByPath( 645 const base::FilePath& directory_path, 646 const ReadDirectoryCallback& callback) { 647 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 648 DCHECK(!callback.is_null()); 649 650 LoadDirectoryIfNeeded( 651 directory_path, 652 base::Bind(&FileSystem::ReadDirectoryByPathAfterLoad, 653 weak_ptr_factory_.GetWeakPtr(), 654 directory_path, 655 callback)); 656 } 657 658 void FileSystem::LoadDirectoryIfNeeded(const base::FilePath& directory_path, 659 const FileOperationCallback& callback) { 660 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 661 DCHECK(!callback.is_null()); 662 663 // ResourceMetadata may know about the entry even if the resource 664 // metadata is not yet fully loaded. 665 resource_metadata_->GetResourceEntryByPathOnUIThread( 666 directory_path, 667 base::Bind(&FileSystem::LoadDirectoryIfNeededAfterGetEntry, 668 weak_ptr_factory_.GetWeakPtr(), 669 directory_path, 670 callback)); 671 } 672 673 void FileSystem::LoadDirectoryIfNeededAfterGetEntry( 674 const base::FilePath& directory_path, 675 const FileOperationCallback& callback, 676 FileError error, 677 scoped_ptr<ResourceEntry> entry) { 678 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 679 DCHECK(!callback.is_null()); 680 681 if (error != FILE_ERROR_OK || 682 entry->resource_id() == util::kDriveOtherDirSpecialResourceId) { 683 // If we don't know about the directory, or it is the "drive/other" 684 // directory that has to gather all orphan entries, start loading full 685 // resource list. 686 change_list_loader_->LoadIfNeeded(DirectoryFetchInfo(), callback); 687 return; 688 } 689 690 if (!entry->file_info().is_directory()) { 691 callback.Run(FILE_ERROR_NOT_A_DIRECTORY); 692 return; 693 } 694 695 // Pass the directory fetch info so we can fetch the contents of the 696 // directory before loading change lists. 697 DirectoryFetchInfo directory_fetch_info( 698 entry->resource_id(), 699 entry->directory_specific_info().changestamp()); 700 change_list_loader_->LoadIfNeeded(directory_fetch_info, callback); 701 } 702 703 void FileSystem::ReadDirectoryByPathAfterLoad( 704 const base::FilePath& directory_path, 705 const ReadDirectoryCallback& callback, 706 FileError error) { 707 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 708 DCHECK(!callback.is_null()); 709 710 DLOG_IF(INFO, error != FILE_ERROR_OK) << "LoadIfNeeded failed. " 711 << FileErrorToString(error); 712 713 resource_metadata_->ReadDirectoryByPathOnUIThread( 714 directory_path, 715 base::Bind(&FileSystem::ReadDirectoryByPathAfterRead, 716 weak_ptr_factory_.GetWeakPtr(), 717 directory_path, 718 callback)); 719 } 720 721 void FileSystem::ReadDirectoryByPathAfterRead( 722 const base::FilePath& directory_path, 723 const ReadDirectoryCallback& callback, 724 FileError error, 725 scoped_ptr<ResourceEntryVector> entries) { 726 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 727 DCHECK(!callback.is_null()); 728 729 if (error != FILE_ERROR_OK) { 730 callback.Run(error, 731 scoped_ptr<ResourceEntryVector>()); 732 return; 733 } 734 DCHECK(entries.get()); // This is valid for empty directories too. 735 736 // TODO(satorux): Stop handling hide_hosted_docs_ here. crbug.com/256520. 737 scoped_ptr<ResourceEntryVector> filtered(new ResourceEntryVector); 738 for (size_t i = 0; i < entries->size(); ++i) { 739 if (hide_hosted_docs_ && 740 entries->at(i).file_specific_info().is_hosted_document()) { 741 continue; 742 } 743 filtered->push_back(entries->at(i)); 744 } 745 746 // Thumbnail URLs are short-lived. We check the validness of the URL in 747 // background, and refresh the metadata for the directory if necessary. 748 // TODO(kinaba): Remove this hack by using persistent URLs crbug.com/254025. 749 CheckStaleThumbnailURL(filtered.get(), 750 base::Bind(&FileSystem::RefreshDirectory, 751 weak_ptr_factory_.GetWeakPtr(), 752 directory_path)); 753 754 callback.Run(FILE_ERROR_OK, filtered.Pass()); 755 } 756 757 void FileSystem::GetAvailableSpace( 758 const GetAvailableSpaceCallback& callback) { 759 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 760 DCHECK(!callback.is_null()); 761 762 scheduler_->GetAboutResource( 763 base::Bind(&FileSystem::OnGetAboutResource, 764 weak_ptr_factory_.GetWeakPtr(), 765 callback)); 766 } 767 768 void FileSystem::OnGetAboutResource( 769 const GetAvailableSpaceCallback& callback, 770 google_apis::GDataErrorCode status, 771 scoped_ptr<google_apis::AboutResource> about_resource) { 772 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 773 DCHECK(!callback.is_null()); 774 775 FileError error = GDataToFileError(status); 776 if (error != FILE_ERROR_OK) { 777 callback.Run(error, -1, -1); 778 return; 779 } 780 DCHECK(about_resource); 781 782 callback.Run(FILE_ERROR_OK, 783 about_resource->quota_bytes_total(), 784 about_resource->quota_bytes_used()); 785 } 786 787 void FileSystem::GetShareUrl( 788 const base::FilePath& file_path, 789 const GURL& embed_origin, 790 const GetShareUrlCallback& callback) { 791 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 792 DCHECK(!callback.is_null()); 793 794 // Resolve the resource id. 795 resource_metadata_->GetResourceEntryByPathOnUIThread( 796 file_path, 797 base::Bind(&FileSystem::GetShareUrlAfterGetResourceEntry, 798 weak_ptr_factory_.GetWeakPtr(), 799 file_path, 800 embed_origin, 801 callback)); 802 } 803 804 void FileSystem::GetShareUrlAfterGetResourceEntry( 805 const base::FilePath& file_path, 806 const GURL& embed_origin, 807 const GetShareUrlCallback& callback, 808 FileError error, 809 scoped_ptr<ResourceEntry> entry) { 810 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 811 DCHECK(!callback.is_null()); 812 813 if (error != FILE_ERROR_OK) { 814 callback.Run(error, GURL()); 815 return; 816 } 817 if (util::IsSpecialResourceId(entry->resource_id())) { 818 // Do not load special directories. Just return. 819 callback.Run(FILE_ERROR_FAILED, GURL()); 820 return; 821 } 822 823 scheduler_->GetShareUrl( 824 entry->resource_id(), 825 embed_origin, 826 ClientContext(USER_INITIATED), 827 base::Bind(&FileSystem::OnGetResourceEntryForGetShareUrl, 828 weak_ptr_factory_.GetWeakPtr(), 829 callback)); 830 } 831 832 void FileSystem::OnGetResourceEntryForGetShareUrl( 833 const GetShareUrlCallback& callback, 834 google_apis::GDataErrorCode status, 835 const GURL& share_url) { 836 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 837 DCHECK(!callback.is_null()); 838 839 FileError error = GDataToFileError(status); 840 if (error != FILE_ERROR_OK) { 841 callback.Run(error, GURL()); 842 return; 843 } 844 845 if (share_url.is_empty()) { 846 callback.Run(FILE_ERROR_FAILED, GURL()); 847 return; 848 } 849 850 callback.Run(FILE_ERROR_OK, share_url); 851 } 852 853 void FileSystem::Search(const std::string& search_query, 854 const GURL& next_url, 855 const SearchCallback& callback) { 856 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 857 DCHECK(!callback.is_null()); 858 search_operation_->Search(search_query, next_url, callback); 859 } 860 861 void FileSystem::SearchMetadata(const std::string& query, 862 int options, 863 int at_most_num_matches, 864 const SearchMetadataCallback& callback) { 865 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 866 867 if (hide_hosted_docs_) 868 options |= SEARCH_METADATA_EXCLUDE_HOSTED_DOCUMENTS; 869 870 drive::internal::SearchMetadata(blocking_task_runner_, 871 resource_metadata_, 872 query, 873 options, 874 at_most_num_matches, 875 callback); 876 } 877 878 void FileSystem::OnDirectoryChangedByOperation( 879 const base::FilePath& directory_path) { 880 OnDirectoryChanged(directory_path); 881 } 882 883 void FileSystem::OnCacheFileUploadNeededByOperation( 884 const std::string& resource_id) { 885 sync_client_->AddUploadTask(resource_id); 886 } 887 888 void FileSystem::OnDirectoryChanged(const base::FilePath& directory_path) { 889 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 890 891 FOR_EACH_OBSERVER(FileSystemObserver, observers_, 892 OnDirectoryChanged(directory_path)); 893 } 894 895 void FileSystem::OnLoadFromServerComplete() { 896 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 897 898 sync_client_->StartCheckingExistingPinnedFiles(); 899 } 900 901 void FileSystem::OnInitialLoadComplete() { 902 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 903 904 blocking_task_runner_->PostTask(FROM_HERE, 905 base::Bind(&internal::RemoveStaleCacheFiles, 906 cache_, 907 resource_metadata_)); 908 sync_client_->StartProcessingBacklog(); 909 } 910 911 void FileSystem::GetMetadata( 912 const GetFilesystemMetadataCallback& callback) { 913 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 914 DCHECK(!callback.is_null()); 915 916 FileSystemMetadata metadata; 917 metadata.refreshing = change_list_loader_->IsRefreshing(); 918 919 // Metadata related to delta update. 920 metadata.last_update_check_time = last_update_check_time_; 921 metadata.last_update_check_error = last_update_check_error_; 922 923 resource_metadata_->GetLargestChangestampOnUIThread( 924 base::Bind(&OnGetLargestChangestamp, metadata, callback)); 925 } 926 927 void FileSystem::MarkCacheFileAsMounted( 928 const base::FilePath& drive_file_path, 929 const MarkMountedCallback& callback) { 930 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 931 DCHECK(!callback.is_null()); 932 933 GetResourceEntryByPath( 934 drive_file_path, 935 base::Bind(&FileSystem::MarkCacheFileAsMountedAfterGetResourceEntry, 936 weak_ptr_factory_.GetWeakPtr(), callback)); 937 } 938 939 void FileSystem::MarkCacheFileAsMountedAfterGetResourceEntry( 940 const MarkMountedCallback& callback, 941 FileError error, 942 scoped_ptr<ResourceEntry> entry) { 943 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 944 DCHECK(!callback.is_null()); 945 946 if (error != FILE_ERROR_OK) { 947 callback.Run(error, base::FilePath()); 948 return; 949 } 950 951 DCHECK(entry); 952 cache_->MarkAsMountedOnUIThread(entry->resource_id(), callback); 953 } 954 955 void FileSystem::MarkCacheFileAsUnmounted( 956 const base::FilePath& cache_file_path, 957 const FileOperationCallback& callback) { 958 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 959 DCHECK(!callback.is_null()); 960 961 if (!cache_->IsUnderFileCacheDirectory(cache_file_path)) { 962 callback.Run(FILE_ERROR_FAILED); 963 return; 964 } 965 cache_->MarkAsUnmountedOnUIThread(cache_file_path, callback); 966 } 967 968 void FileSystem::GetCacheEntryByResourceId( 969 const std::string& resource_id, 970 const GetCacheEntryCallback& callback) { 971 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 972 DCHECK(!resource_id.empty()); 973 DCHECK(!callback.is_null()); 974 975 cache_->GetCacheEntryOnUIThread(resource_id, callback); 976 } 977 978 void FileSystem::OnDisableDriveHostedFilesChanged() { 979 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 980 SetHideHostedDocuments( 981 pref_service_->GetBoolean(prefs::kDisableDriveHostedFiles)); 982 } 983 984 void FileSystem::SetHideHostedDocuments(bool hide) { 985 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 986 987 if (hide == hide_hosted_docs_) 988 return; 989 990 hide_hosted_docs_ = hide; 991 992 // Kick off directory refresh when this setting changes. 993 FOR_EACH_OBSERVER(FileSystemObserver, observers_, 994 OnDirectoryChanged(util::GetDriveGrandRootPath())); 995 } 996 997 void FileSystem::InitializePreferenceObserver() { 998 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 999 1000 pref_registrar_.reset(new PrefChangeRegistrar()); 1001 pref_registrar_->Init(pref_service_); 1002 pref_registrar_->Add( 1003 prefs::kDisableDriveHostedFiles, 1004 base::Bind(&FileSystem::OnDisableDriveHostedFilesChanged, 1005 base::Unretained(this))); 1006 } 1007 1008 void FileSystem::OpenFile(const base::FilePath& file_path, 1009 OpenMode open_mode, 1010 const OpenFileCallback& callback) { 1011 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 1012 DCHECK(!callback.is_null()); 1013 1014 open_file_operation_->OpenFile(file_path, open_mode, callback); 1015 } 1016 1017 void FileSystem::RefreshDirectory(const base::FilePath& directory_path) { 1018 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 1019 1020 resource_metadata_->GetResourceEntryByPathOnUIThread( 1021 directory_path, 1022 base::Bind(&FileSystem::RefreshDirectoryAfterGetResourceEntry, 1023 weak_ptr_factory_.GetWeakPtr(), 1024 directory_path)); 1025 } 1026 1027 void FileSystem::RefreshDirectoryAfterGetResourceEntry( 1028 const base::FilePath& directory_path, 1029 FileError error, 1030 scoped_ptr<ResourceEntry> entry) { 1031 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 1032 1033 if (error != FILE_ERROR_OK || !entry->file_info().is_directory()) 1034 return; 1035 1036 // Do not load special directories. Just return. 1037 const std::string& id = entry->resource_id(); 1038 if (util::IsSpecialResourceId(id)) 1039 return; 1040 1041 util::Log(logging::LOG_INFO, 1042 "Thumbnail refresh for %s", directory_path.AsUTF8Unsafe().c_str()); 1043 change_list_loader_->LoadDirectoryFromServer( 1044 id, base::Bind(&util::EmptyFileOperationCallback)); 1045 } 1046 1047 } // namespace drive 1048