| 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.h" | 5 #include "chrome/browser/chromeos/drive/file_system.h" |
| 6 | 6 |
| 7 #include "base/bind.h" | 7 #include "base/bind.h" |
| 8 #include "base/file_util.h" | 8 #include "base/file_util.h" |
| 9 #include "base/message_loop/message_loop_proxy.h" | 9 #include "base/message_loop/message_loop_proxy.h" |
| 10 #include "base/metrics/histogram.h" | 10 #include "base/metrics/histogram.h" |
| (...skipping 21 matching lines...) Expand all Loading... |
| 32 #include "content/public/browser/browser_thread.h" | 32 #include "content/public/browser/browser_thread.h" |
| 33 #include "content/public/browser/notification_details.h" | 33 #include "content/public/browser/notification_details.h" |
| 34 | 34 |
| 35 using content::BrowserThread; | 35 using content::BrowserThread; |
| 36 | 36 |
| 37 namespace drive { | 37 namespace drive { |
| 38 namespace { | 38 namespace { |
| 39 | 39 |
| 40 //================================ Helper functions ============================ | 40 //================================ Helper functions ============================ |
| 41 | 41 |
| 42 // Creates a temporary JSON file representing a document with |alternate_url| | |
| 43 // and |resource_id| under |document_dir| on blocking pool. | |
| 44 FileError CreateDocumentJsonFileOnBlockingPool( | |
| 45 const base::FilePath& document_dir, | |
| 46 const GURL& alternate_url, | |
| 47 const std::string& resource_id, | |
| 48 base::FilePath* temp_file_path) { | |
| 49 DCHECK(temp_file_path); | |
| 50 | |
| 51 if (!file_util::CreateTemporaryFileInDir(document_dir, temp_file_path) || | |
| 52 !util::CreateGDocFile(*temp_file_path, alternate_url, resource_id)) | |
| 53 return FILE_ERROR_FAILED; | |
| 54 return FILE_ERROR_OK; | |
| 55 } | |
| 56 | |
| 57 // Helper function for binding |path| to GetResourceEntryWithFilePathCallback | 42 // Helper function for binding |path| to GetResourceEntryWithFilePathCallback |
| 58 // and create GetResourceEntryCallback. | 43 // and create GetResourceEntryCallback. |
| 59 void RunGetResourceEntryWithFilePathCallback( | 44 void RunGetResourceEntryWithFilePathCallback( |
| 60 const GetResourceEntryWithFilePathCallback& callback, | 45 const GetResourceEntryWithFilePathCallback& callback, |
| 61 const base::FilePath& path, | 46 const base::FilePath& path, |
| 62 FileError error, | 47 FileError error, |
| 63 scoped_ptr<ResourceEntry> entry) { | 48 scoped_ptr<ResourceEntry> entry) { |
| 64 DCHECK(!callback.is_null()); | 49 DCHECK(!callback.is_null()); |
| 65 callback.Run(error, path, entry.Pass()); | 50 callback.Run(error, path, entry.Pass()); |
| 66 } | 51 } |
| (...skipping 13 matching lines...) Expand all Loading... |
| 80 | 65 |
| 81 // Thin adapter to map GetFileCallback to FileOperationCallback. | 66 // Thin adapter to map GetFileCallback to FileOperationCallback. |
| 82 void GetFileCallbackToFileOperationCallbackAdapter( | 67 void GetFileCallbackToFileOperationCallbackAdapter( |
| 83 const FileOperationCallback& callback, | 68 const FileOperationCallback& callback, |
| 84 FileError error, | 69 FileError error, |
| 85 const base::FilePath& unused_file_path, | 70 const base::FilePath& unused_file_path, |
| 86 scoped_ptr<ResourceEntry> unused_entry) { | 71 scoped_ptr<ResourceEntry> unused_entry) { |
| 87 callback.Run(error); | 72 callback.Run(error); |
| 88 } | 73 } |
| 89 | 74 |
| 90 // Creates a file with unique name in |dir| and stores the path to |temp_file|. | |
| 91 // Additionally, sets the permission of the file to allow read access from | |
| 92 // others and group member users (i.e, "-rw-r--r--"). | |
| 93 // We need this wrapper because Drive cache files may be read from other | |
| 94 // processes (e.g., cros_disks for mounting zip files). | |
| 95 // | |
| 96 // Must be called on the blocking pool. | |
| 97 bool CreateTemporaryReadableFileInDir(const base::FilePath& dir, | |
| 98 base::FilePath* temp_file) { | |
| 99 if (!file_util::CreateTemporaryFileInDir(dir, temp_file)) | |
| 100 return false; | |
| 101 return file_util::SetPosixFilePermissions( | |
| 102 *temp_file, | |
| 103 file_util::FILE_PERMISSION_READ_BY_USER | | |
| 104 file_util::FILE_PERMISSION_WRITE_BY_USER | | |
| 105 file_util::FILE_PERMISSION_READ_BY_GROUP | | |
| 106 file_util::FILE_PERMISSION_READ_BY_OTHERS); | |
| 107 } | |
| 108 | |
| 109 } // namespace | 75 } // namespace |
| 110 | 76 |
| 111 // FileSystem::GetFileCompleteForOpenParams struct implementation. | |
| 112 struct FileSystem::GetFileCompleteForOpenParams { | |
| 113 GetFileCompleteForOpenParams(const OpenFileCallback& callback, | |
| 114 const std::string& resource_id, | |
| 115 const std::string& md5); | |
| 116 OpenFileCallback callback; | |
| 117 std::string resource_id; | |
| 118 std::string md5; | |
| 119 }; | |
| 120 | |
| 121 FileSystem::GetFileCompleteForOpenParams::GetFileCompleteForOpenParams( | |
| 122 const OpenFileCallback& callback, | |
| 123 const std::string& resource_id, | |
| 124 const std::string& md5) | |
| 125 : callback(callback), | |
| 126 resource_id(resource_id), | |
| 127 md5(md5) { | |
| 128 } | |
| 129 | |
| 130 // FileSystem::GetResolvedFileParams struct implementation. | |
| 131 struct FileSystem::GetResolvedFileParams { | |
| 132 GetResolvedFileParams( | |
| 133 const base::FilePath& drive_file_path, | |
| 134 const DriveClientContext& context, | |
| 135 scoped_ptr<ResourceEntry> entry, | |
| 136 const GetFileContentInitializedCallback& initialized_callback, | |
| 137 const GetFileCallback& get_file_callback, | |
| 138 const google_apis::GetContentCallback& get_content_callback) | |
| 139 : drive_file_path(drive_file_path), | |
| 140 context(context), | |
| 141 entry(entry.Pass()), | |
| 142 initialized_callback(initialized_callback), | |
| 143 get_file_callback(get_file_callback), | |
| 144 get_content_callback(get_content_callback) { | |
| 145 DCHECK(!get_file_callback.is_null()); | |
| 146 DCHECK(this->entry); | |
| 147 } | |
| 148 | |
| 149 void OnError(FileError error) { | |
| 150 get_file_callback.Run(error, base::FilePath(), scoped_ptr<ResourceEntry>()); | |
| 151 } | |
| 152 | |
| 153 void OnCacheFileFound(const base::FilePath& local_file_path) { | |
| 154 if (initialized_callback.is_null()) { | |
| 155 return; | |
| 156 } | |
| 157 | |
| 158 scoped_ptr<ResourceEntry> new_entry(new ResourceEntry(*entry)); | |
| 159 initialized_callback.Run(FILE_ERROR_OK, | |
| 160 new_entry.Pass(), | |
| 161 local_file_path, | |
| 162 base::Closure()); | |
| 163 } | |
| 164 | |
| 165 void OnStartDownloading(const base::Closure& cancel_download_closure) { | |
| 166 if (initialized_callback.is_null()) { | |
| 167 return; | |
| 168 } | |
| 169 | |
| 170 scoped_ptr<ResourceEntry> new_entry(new ResourceEntry(*entry)); | |
| 171 initialized_callback.Run(FILE_ERROR_OK, | |
| 172 new_entry.Pass(), | |
| 173 base::FilePath(), | |
| 174 cancel_download_closure); | |
| 175 } | |
| 176 | |
| 177 void OnComplete(const base::FilePath& local_file_path) { | |
| 178 get_file_callback.Run(FILE_ERROR_OK, local_file_path, | |
| 179 scoped_ptr<ResourceEntry>(new ResourceEntry(*entry))); | |
| 180 } | |
| 181 | |
| 182 const base::FilePath drive_file_path; | |
| 183 const DriveClientContext context; | |
| 184 scoped_ptr<ResourceEntry> entry; | |
| 185 const GetFileContentInitializedCallback initialized_callback; | |
| 186 const GetFileCallback get_file_callback; | |
| 187 const google_apis::GetContentCallback get_content_callback; | |
| 188 }; | |
| 189 | |
| 190 FileSystem::FileSystem( | 77 FileSystem::FileSystem( |
| 191 Profile* profile, | 78 Profile* profile, |
| 192 internal::FileCache* cache, | 79 internal::FileCache* cache, |
| 193 google_apis::DriveServiceInterface* drive_service, | 80 google_apis::DriveServiceInterface* drive_service, |
| 194 JobScheduler* scheduler, | 81 JobScheduler* scheduler, |
| 195 internal::ResourceMetadata* resource_metadata, | 82 internal::ResourceMetadata* resource_metadata, |
| 196 base::SequencedTaskRunner* blocking_task_runner) | 83 base::SequencedTaskRunner* blocking_task_runner) |
| 197 : profile_(profile), | 84 : profile_(profile), |
| 198 cache_(cache), | 85 cache_(cache), |
| 199 drive_service_(drive_service), | 86 drive_service_(drive_service), |
| (...skipping 287 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 487 | 374 |
| 488 cache_->UnpinOnUIThread(entry->resource_id(), | 375 cache_->UnpinOnUIThread(entry->resource_id(), |
| 489 entry->file_specific_info().file_md5(), callback); | 376 entry->file_specific_info().file_md5(), callback); |
| 490 } | 377 } |
| 491 | 378 |
| 492 void FileSystem::GetFileByPath(const base::FilePath& file_path, | 379 void FileSystem::GetFileByPath(const base::FilePath& file_path, |
| 493 const GetFileCallback& callback) { | 380 const GetFileCallback& callback) { |
| 494 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 381 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 495 DCHECK(!callback.is_null()); | 382 DCHECK(!callback.is_null()); |
| 496 | 383 |
| 497 resource_metadata_->GetResourceEntryByPathOnUIThread( | 384 operations_.EnsureFileDownloaded( |
| 498 file_path, | 385 file_path, |
| 499 base::Bind(&FileSystem::OnGetResourceEntryCompleteForGetFileByPath, | 386 DriveClientContext(USER_INITIATED), |
| 500 weak_ptr_factory_.GetWeakPtr(), | 387 GetFileContentInitializedCallback(), |
| 501 file_path, | 388 google_apis::GetContentCallback(), |
| 502 callback)); | 389 callback); |
| 503 } | |
| 504 | |
| 505 void FileSystem::OnGetResourceEntryCompleteForGetFileByPath( | |
| 506 const base::FilePath& file_path, | |
| 507 const GetFileCallback& callback, | |
| 508 FileError error, | |
| 509 scoped_ptr<ResourceEntry> entry) { | |
| 510 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 511 DCHECK(!callback.is_null()); | |
| 512 | |
| 513 if (error != FILE_ERROR_OK) { | |
| 514 callback.Run(error, base::FilePath(), scoped_ptr<ResourceEntry>()); | |
| 515 return; | |
| 516 } | |
| 517 DCHECK(entry); | |
| 518 | |
| 519 GetResolvedFileByPath( | |
| 520 make_scoped_ptr(new GetResolvedFileParams( | |
| 521 file_path, | |
| 522 DriveClientContext(USER_INITIATED), | |
| 523 entry.Pass(), | |
| 524 GetFileContentInitializedCallback(), | |
| 525 callback, | |
| 526 google_apis::GetContentCallback()))); | |
| 527 } | 390 } |
| 528 | 391 |
| 529 void FileSystem::GetFileByResourceId( | 392 void FileSystem::GetFileByResourceId( |
| 530 const std::string& resource_id, | 393 const std::string& resource_id, |
| 531 const DriveClientContext& context, | 394 const DriveClientContext& context, |
| 532 const GetFileCallback& get_file_callback, | 395 const GetFileCallback& get_file_callback, |
| 533 const google_apis::GetContentCallback& get_content_callback) { | 396 const google_apis::GetContentCallback& get_content_callback) { |
| 534 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 397 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 535 DCHECK(!resource_id.empty()); | 398 DCHECK(!resource_id.empty()); |
| 536 DCHECK(!get_file_callback.is_null()); | 399 DCHECK(!get_file_callback.is_null()); |
| (...skipping 16 matching lines...) Expand all Loading... |
| 553 scoped_ptr<ResourceEntry> entry) { | 416 scoped_ptr<ResourceEntry> entry) { |
| 554 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 417 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 555 DCHECK(!get_file_callback.is_null()); | 418 DCHECK(!get_file_callback.is_null()); |
| 556 | 419 |
| 557 if (error != FILE_ERROR_OK) { | 420 if (error != FILE_ERROR_OK) { |
| 558 get_file_callback.Run(FILE_ERROR_NOT_FOUND, base::FilePath(), | 421 get_file_callback.Run(FILE_ERROR_NOT_FOUND, base::FilePath(), |
| 559 scoped_ptr<ResourceEntry>()); | 422 scoped_ptr<ResourceEntry>()); |
| 560 return; | 423 return; |
| 561 } | 424 } |
| 562 | 425 |
| 563 GetResolvedFileByPath( | 426 operations_.EnsureFileDownloaded( |
| 564 make_scoped_ptr(new GetResolvedFileParams( | 427 file_path, |
| 565 file_path, | 428 context, |
| 566 context, | 429 GetFileContentInitializedCallback(), |
| 567 entry.Pass(), | 430 get_content_callback, |
| 568 GetFileContentInitializedCallback(), | 431 get_file_callback); |
| 569 get_file_callback, | |
| 570 get_content_callback))); | |
| 571 } | 432 } |
| 572 | 433 |
| 573 void FileSystem::GetFileContentByPath( | 434 void FileSystem::GetFileContentByPath( |
| 574 const base::FilePath& file_path, | 435 const base::FilePath& file_path, |
| 575 const GetFileContentInitializedCallback& initialized_callback, | 436 const GetFileContentInitializedCallback& initialized_callback, |
| 576 const google_apis::GetContentCallback& get_content_callback, | 437 const google_apis::GetContentCallback& get_content_callback, |
| 577 const FileOperationCallback& completion_callback) { | 438 const FileOperationCallback& completion_callback) { |
| 578 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 439 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 579 DCHECK(!initialized_callback.is_null()); | 440 DCHECK(!initialized_callback.is_null()); |
| 580 DCHECK(!get_content_callback.is_null()); | 441 DCHECK(!get_content_callback.is_null()); |
| 581 DCHECK(!completion_callback.is_null()); | 442 DCHECK(!completion_callback.is_null()); |
| 582 | 443 |
| 583 resource_metadata_->GetResourceEntryByPathOnUIThread( | 444 operations_.EnsureFileDownloaded( |
| 584 file_path, | 445 file_path, |
| 585 base::Bind(&FileSystem::GetFileContentByPathAfterGetEntry, | 446 DriveClientContext(USER_INITIATED), |
| 586 weak_ptr_factory_.GetWeakPtr(), | 447 initialized_callback, |
| 587 file_path, | 448 get_content_callback, |
| 588 initialized_callback, | 449 base::Bind(&GetFileCallbackToFileOperationCallbackAdapter, |
| 589 get_content_callback, | |
| 590 completion_callback)); | 450 completion_callback)); |
| 591 } | 451 } |
| 592 | 452 |
| 593 void FileSystem::GetFileContentByPathAfterGetEntry( | |
| 594 const base::FilePath& file_path, | |
| 595 const GetFileContentInitializedCallback& initialized_callback, | |
| 596 const google_apis::GetContentCallback& get_content_callback, | |
| 597 const FileOperationCallback& completion_callback, | |
| 598 FileError error, | |
| 599 scoped_ptr<ResourceEntry> entry) { | |
| 600 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 601 DCHECK(!initialized_callback.is_null()); | |
| 602 DCHECK(!get_content_callback.is_null()); | |
| 603 DCHECK(!completion_callback.is_null()); | |
| 604 | |
| 605 if (error != FILE_ERROR_OK) { | |
| 606 completion_callback.Run(error); | |
| 607 return; | |
| 608 } | |
| 609 | |
| 610 DCHECK(entry); | |
| 611 GetResolvedFileByPath( | |
| 612 make_scoped_ptr(new GetResolvedFileParams( | |
| 613 file_path, | |
| 614 DriveClientContext(USER_INITIATED), | |
| 615 entry.Pass(), | |
| 616 initialized_callback, | |
| 617 base::Bind(&GetFileCallbackToFileOperationCallbackAdapter, | |
| 618 completion_callback), | |
| 619 get_content_callback))); | |
| 620 } | |
| 621 | |
| 622 void FileSystem::GetResourceEntryByPath( | 453 void FileSystem::GetResourceEntryByPath( |
| 623 const base::FilePath& file_path, | 454 const base::FilePath& file_path, |
| 624 const GetResourceEntryCallback& callback) { | 455 const GetResourceEntryCallback& callback) { |
| 625 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 456 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 626 DCHECK(!callback.is_null()); | 457 DCHECK(!callback.is_null()); |
| 627 | 458 |
| 628 // ResourceMetadata may know about the entry even if the resource | 459 // ResourceMetadata may know about the entry even if the resource |
| 629 // metadata is not yet fully loaded. For instance, ResourceMetadata() | 460 // metadata is not yet fully loaded. For instance, ResourceMetadata() |
| 630 // always knows about the root directory. For "fast fetch" | 461 // always knows about the root directory. For "fast fetch" |
| 631 // (crbug.com/178348) to work, it's needed to delay the resource metadata | 462 // (crbug.com/178348) to work, it's needed to delay the resource metadata |
| (...skipping 156 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 788 callback.Run(error, | 619 callback.Run(error, |
| 789 hide_hosted_docs_, | 620 hide_hosted_docs_, |
| 790 scoped_ptr<ResourceEntryVector>()); | 621 scoped_ptr<ResourceEntryVector>()); |
| 791 return; | 622 return; |
| 792 } | 623 } |
| 793 DCHECK(entries.get()); // This is valid for empty directories too. | 624 DCHECK(entries.get()); // This is valid for empty directories too. |
| 794 | 625 |
| 795 callback.Run(FILE_ERROR_OK, hide_hosted_docs_, entries.Pass()); | 626 callback.Run(FILE_ERROR_OK, hide_hosted_docs_, entries.Pass()); |
| 796 } | 627 } |
| 797 | 628 |
| 798 void FileSystem::GetResolvedFileByPath( | |
| 799 scoped_ptr<GetResolvedFileParams> params) { | |
| 800 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 801 DCHECK(params); | |
| 802 | |
| 803 if (params->entry->file_info().is_directory()) { | |
| 804 params->OnError(FILE_ERROR_NOT_A_FILE); | |
| 805 return; | |
| 806 } | |
| 807 | |
| 808 // The file's entry should have its file specific info. | |
| 809 DCHECK(params->entry->has_file_specific_info()); | |
| 810 | |
| 811 // For a hosted document, we create a special JSON file to represent the | |
| 812 // document instead of fetching the document content in one of the exported | |
| 813 // formats. The JSON file contains the edit URL and resource ID of the | |
| 814 // document. | |
| 815 if (params->entry->file_specific_info().is_hosted_document()) { | |
| 816 base::FilePath* temp_file_path = new base::FilePath; | |
| 817 ResourceEntry* entry_ptr = params->entry.get(); | |
| 818 base::PostTaskAndReplyWithResult( | |
| 819 blocking_task_runner_, | |
| 820 FROM_HERE, | |
| 821 base::Bind(&CreateDocumentJsonFileOnBlockingPool, | |
| 822 cache_->GetCacheDirectoryPath( | |
| 823 internal::FileCache::CACHE_TYPE_TMP_DOCUMENTS), | |
| 824 GURL(entry_ptr->file_specific_info().alternate_url()), | |
| 825 entry_ptr->resource_id(), | |
| 826 temp_file_path), | |
| 827 base::Bind( | |
| 828 &FileSystem::GetResolvedFileByPathAfterCreateDocumentJsonFile, | |
| 829 weak_ptr_factory_.GetWeakPtr(), | |
| 830 base::Passed(¶ms), | |
| 831 base::Owned(temp_file_path))); | |
| 832 return; | |
| 833 } | |
| 834 | |
| 835 // Returns absolute path of the file if it were cached or to be cached. | |
| 836 ResourceEntry* entry_ptr = params->entry.get(); | |
| 837 cache_->GetFileOnUIThread( | |
| 838 entry_ptr->resource_id(), | |
| 839 entry_ptr->file_specific_info().file_md5(), | |
| 840 base::Bind( | |
| 841 &FileSystem::GetResolvedFileByPathAfterGetFileFromCache, | |
| 842 weak_ptr_factory_.GetWeakPtr(), | |
| 843 base::Passed(¶ms))); | |
| 844 } | |
| 845 | |
| 846 void FileSystem::GetResolvedFileByPathAfterCreateDocumentJsonFile( | |
| 847 scoped_ptr<GetResolvedFileParams> params, | |
| 848 const base::FilePath* file_path, | |
| 849 FileError error) { | |
| 850 DCHECK(params); | |
| 851 DCHECK(file_path); | |
| 852 | |
| 853 if (error != FILE_ERROR_OK) { | |
| 854 params->OnError(error); | |
| 855 return; | |
| 856 } | |
| 857 | |
| 858 params->OnCacheFileFound(*file_path); | |
| 859 params->OnComplete(*file_path); | |
| 860 } | |
| 861 | |
| 862 void FileSystem::GetResolvedFileByPathAfterGetFileFromCache( | |
| 863 scoped_ptr<GetResolvedFileParams> params, | |
| 864 FileError error, | |
| 865 const base::FilePath& cache_file_path) { | |
| 866 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 867 DCHECK(params); | |
| 868 | |
| 869 // Have we found the file in cache? If so, return it back to the caller. | |
| 870 if (error == FILE_ERROR_OK) { | |
| 871 params->OnCacheFileFound(cache_file_path); | |
| 872 params->OnComplete(cache_file_path); | |
| 873 return; | |
| 874 } | |
| 875 | |
| 876 // If cache file is not found, try to download the file from the server | |
| 877 // instead. This logic is rather complicated but here's how this works: | |
| 878 // | |
| 879 // Retrieve fresh file metadata from server. We will extract file size and | |
| 880 // download url from there. Note that the download url is transient. | |
| 881 // | |
| 882 // Check if we have enough space, based on the expected file size. | |
| 883 // - if we don't have enough space, try to free up the disk space | |
| 884 // - if we still don't have enough space, return "no space" error | |
| 885 // - if we have enough space, start downloading the file from the server | |
| 886 GetResolvedFileParams* params_ptr = params.get(); | |
| 887 scheduler_->GetResourceEntry( | |
| 888 params_ptr->entry->resource_id(), | |
| 889 params_ptr->context, | |
| 890 base::Bind(&FileSystem::GetResolvedFileByPathAfterGetResourceEntry, | |
| 891 weak_ptr_factory_.GetWeakPtr(), | |
| 892 base::Passed(¶ms))); | |
| 893 } | |
| 894 | |
| 895 void FileSystem::GetResolvedFileByPathAfterGetResourceEntry( | |
| 896 scoped_ptr<GetResolvedFileParams> params, | |
| 897 google_apis::GDataErrorCode status, | |
| 898 scoped_ptr<google_apis::ResourceEntry> entry) { | |
| 899 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 900 DCHECK(params); | |
| 901 | |
| 902 const FileError error = util::GDataToFileError(status); | |
| 903 if (error != FILE_ERROR_OK) { | |
| 904 params->OnError(error); | |
| 905 return; | |
| 906 } | |
| 907 | |
| 908 // The download URL is: | |
| 909 // 1) src attribute of content element, on GData WAPI. | |
| 910 // 2) the value of the key 'downloadUrl', on Drive API v2. | |
| 911 // In both cases, we can use ResourceEntry::download_url(). | |
| 912 const GURL& download_url = entry->download_url(); | |
| 913 | |
| 914 // The download URL can be empty for non-downloadable files (such as files | |
| 915 // shared from others with "prevent downloading by viewers" flag set.) | |
| 916 if (download_url.is_empty()) { | |
| 917 params->OnError(FILE_ERROR_ACCESS_DENIED); | |
| 918 return; | |
| 919 } | |
| 920 | |
| 921 DCHECK_EQ(params->entry->resource_id(), entry->resource_id()); | |
| 922 resource_metadata_->RefreshEntryOnUIThread( | |
| 923 ConvertToResourceEntry(*entry), | |
| 924 base::Bind(&FileSystem::GetResolvedFileByPathAfterRefreshEntry, | |
| 925 weak_ptr_factory_.GetWeakPtr(), | |
| 926 base::Passed(¶ms), | |
| 927 download_url)); | |
| 928 } | |
| 929 | |
| 930 void FileSystem::GetResolvedFileByPathAfterRefreshEntry( | |
| 931 scoped_ptr<GetResolvedFileParams> params, | |
| 932 const GURL& download_url, | |
| 933 FileError error, | |
| 934 const base::FilePath& drive_file_path, | |
| 935 scoped_ptr<ResourceEntry> entry) { | |
| 936 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 937 DCHECK(params); | |
| 938 | |
| 939 if (error != FILE_ERROR_OK) { | |
| 940 params->OnError(error); | |
| 941 return; | |
| 942 } | |
| 943 | |
| 944 int64 file_size = entry->file_info().size(); | |
| 945 params->entry = entry.Pass(); // Update the entry in |params|. | |
| 946 cache_->FreeDiskSpaceIfNeededForOnUIThread( | |
| 947 file_size, | |
| 948 base::Bind(&FileSystem::GetResolvedFileByPathAfterFreeDiskSpace, | |
| 949 weak_ptr_factory_.GetWeakPtr(), | |
| 950 base::Passed(¶ms), | |
| 951 download_url)); | |
| 952 } | |
| 953 | |
| 954 void FileSystem::GetResolvedFileByPathAfterFreeDiskSpace( | |
| 955 scoped_ptr<GetResolvedFileParams> params, | |
| 956 const GURL& download_url, | |
| 957 bool has_enough_space) { | |
| 958 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 959 DCHECK(params); | |
| 960 | |
| 961 if (!has_enough_space) { | |
| 962 // If no enough space, return FILE_ERROR_NO_SPACE. | |
| 963 params->OnError(FILE_ERROR_NO_SPACE); | |
| 964 return; | |
| 965 } | |
| 966 | |
| 967 // We have enough disk space. Create download destination file. | |
| 968 const base::FilePath temp_download_directory = cache_->GetCacheDirectoryPath( | |
| 969 internal::FileCache::CACHE_TYPE_TMP_DOWNLOADS); | |
| 970 base::FilePath* file_path = new base::FilePath; | |
| 971 base::PostTaskAndReplyWithResult( | |
| 972 blocking_task_runner_, | |
| 973 FROM_HERE, | |
| 974 base::Bind(&CreateTemporaryReadableFileInDir, | |
| 975 temp_download_directory, | |
| 976 file_path), | |
| 977 base::Bind(&FileSystem::GetResolveFileByPathAfterCreateTemporaryFile, | |
| 978 weak_ptr_factory_.GetWeakPtr(), | |
| 979 base::Passed(¶ms), | |
| 980 download_url, | |
| 981 base::Owned(file_path))); | |
| 982 } | |
| 983 | |
| 984 void FileSystem::GetResolveFileByPathAfterCreateTemporaryFile( | |
| 985 scoped_ptr<GetResolvedFileParams> params, | |
| 986 const GURL& download_url, | |
| 987 base::FilePath* temp_file, | |
| 988 bool success) { | |
| 989 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 990 DCHECK(params); | |
| 991 | |
| 992 if (!success) { | |
| 993 params->OnError(FILE_ERROR_FAILED); | |
| 994 return; | |
| 995 } | |
| 996 | |
| 997 GetResolvedFileParams* params_ptr = params.get(); | |
| 998 JobID id = scheduler_->DownloadFile( | |
| 999 params_ptr->drive_file_path, | |
| 1000 *temp_file, | |
| 1001 download_url, | |
| 1002 params_ptr->context, | |
| 1003 base::Bind(&FileSystem::GetResolvedFileByPathAfterDownloadFile, | |
| 1004 weak_ptr_factory_.GetWeakPtr(), | |
| 1005 base::Passed(¶ms)), | |
| 1006 params_ptr->get_content_callback); | |
| 1007 params_ptr->OnStartDownloading( | |
| 1008 base::Bind(&FileSystem::CancelJobInScheduler, | |
| 1009 weak_ptr_factory_.GetWeakPtr(), | |
| 1010 id)); | |
| 1011 } | |
| 1012 | |
| 1013 void FileSystem::GetResolvedFileByPathAfterDownloadFile( | |
| 1014 scoped_ptr<GetResolvedFileParams> params, | |
| 1015 google_apis::GDataErrorCode status, | |
| 1016 const base::FilePath& downloaded_file_path) { | |
| 1017 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 1018 DCHECK(params); | |
| 1019 | |
| 1020 // If user cancels download of a pinned-but-not-fetched file, mark file as | |
| 1021 // unpinned so that we do not sync the file again. | |
| 1022 if (status == google_apis::GDATA_CANCELLED) { | |
| 1023 cache_->GetCacheEntryOnUIThread( | |
| 1024 params->entry->resource_id(), | |
| 1025 params->entry->file_specific_info().file_md5(), | |
| 1026 base::Bind( | |
| 1027 &FileSystem::GetResolvedFileByPathAfterGetCacheEntryForCancel, | |
| 1028 weak_ptr_factory_.GetWeakPtr(), | |
| 1029 params->entry->resource_id(), | |
| 1030 params->entry->file_specific_info().file_md5())); | |
| 1031 } | |
| 1032 | |
| 1033 FileError error = util::GDataToFileError(status); | |
| 1034 if (error != FILE_ERROR_OK) { | |
| 1035 params->OnError(error); | |
| 1036 return; | |
| 1037 } | |
| 1038 | |
| 1039 ResourceEntry* entry = params->entry.get(); | |
| 1040 cache_->StoreOnUIThread( | |
| 1041 entry->resource_id(), | |
| 1042 entry->file_specific_info().file_md5(), | |
| 1043 downloaded_file_path, | |
| 1044 internal::FileCache::FILE_OPERATION_MOVE, | |
| 1045 base::Bind(&FileSystem::GetResolvedFileByPathAfterStore, | |
| 1046 weak_ptr_factory_.GetWeakPtr(), | |
| 1047 base::Passed(¶ms), | |
| 1048 downloaded_file_path)); | |
| 1049 } | |
| 1050 | |
| 1051 void FileSystem::GetResolvedFileByPathAfterGetCacheEntryForCancel( | |
| 1052 const std::string& resource_id, | |
| 1053 const std::string& md5, | |
| 1054 bool success, | |
| 1055 const FileCacheEntry& cache_entry) { | |
| 1056 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 1057 // TODO(hshi): http://crbug.com/127138 notify when file properties change. | |
| 1058 // This allows file manager to clear the "Available offline" checkbox. | |
| 1059 if (success && cache_entry.is_pinned()) { | |
| 1060 cache_->UnpinOnUIThread(resource_id, | |
| 1061 md5, | |
| 1062 base::Bind(&util::EmptyFileOperationCallback)); | |
| 1063 } | |
| 1064 } | |
| 1065 | |
| 1066 void FileSystem::GetResolvedFileByPathAfterStore( | |
| 1067 scoped_ptr<GetResolvedFileParams> params, | |
| 1068 const base::FilePath& downloaded_file_path, | |
| 1069 FileError error) { | |
| 1070 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 1071 DCHECK(params); | |
| 1072 | |
| 1073 if (error != FILE_ERROR_OK) { | |
| 1074 blocking_task_runner_->PostTask( | |
| 1075 FROM_HERE, | |
| 1076 base::Bind(base::IgnoreResult(&file_util::Delete), | |
| 1077 downloaded_file_path, | |
| 1078 false /* recursive*/)); | |
| 1079 params->OnError(error); | |
| 1080 return; | |
| 1081 } | |
| 1082 // Storing to cache changes the "offline available" status, hence notify. | |
| 1083 OnDirectoryChanged(params->drive_file_path.DirName()); | |
| 1084 | |
| 1085 ResourceEntry* entry = params->entry.get(); | |
| 1086 cache_->GetFileOnUIThread( | |
| 1087 entry->resource_id(), | |
| 1088 entry->file_specific_info().file_md5(), | |
| 1089 base::Bind(&FileSystem::GetResolvedFileByPathAfterGetFile, | |
| 1090 weak_ptr_factory_.GetWeakPtr(), | |
| 1091 base::Passed(¶ms))); | |
| 1092 } | |
| 1093 | |
| 1094 void FileSystem::GetResolvedFileByPathAfterGetFile( | |
| 1095 scoped_ptr<GetResolvedFileParams> params, | |
| 1096 FileError error, | |
| 1097 const base::FilePath& cache_file) { | |
| 1098 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 1099 DCHECK(params); | |
| 1100 | |
| 1101 if (error != FILE_ERROR_OK) { | |
| 1102 params->OnError(error); | |
| 1103 return; | |
| 1104 } | |
| 1105 params->OnComplete(cache_file); | |
| 1106 } | |
| 1107 | |
| 1108 void FileSystem::RefreshDirectory( | 629 void FileSystem::RefreshDirectory( |
| 1109 const base::FilePath& directory_path, | 630 const base::FilePath& directory_path, |
| 1110 const FileOperationCallback& callback) { | 631 const FileOperationCallback& callback) { |
| 1111 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 632 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 1112 DCHECK(!callback.is_null()); | 633 DCHECK(!callback.is_null()); |
| 1113 | 634 |
| 1114 // Make sure the destination directory exists. | 635 // Make sure the destination directory exists. |
| 1115 resource_metadata_->GetResourceEntryByPathOnUIThread( | 636 resource_metadata_->GetResourceEntryByPathOnUIThread( |
| 1116 directory_path, | 637 directory_path, |
| 1117 base::Bind(&FileSystem::RefreshDirectoryAfterGetResourceEntry, | 638 base::Bind(&FileSystem::RefreshDirectoryAfterGetResourceEntry, |
| (...skipping 242 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1360 // Open->Open->modify->Close->modify->Close; the second modify may not be | 881 // Open->Open->modify->Close->modify->Close; the second modify may not be |
| 1361 // synchronized to the server since it is already Closed on the cache). | 882 // synchronized to the server since it is already Closed on the cache). |
| 1362 if (open_files_.find(file_path) != open_files_.end()) { | 883 if (open_files_.find(file_path) != open_files_.end()) { |
| 1363 base::MessageLoopProxy::current()->PostTask( | 884 base::MessageLoopProxy::current()->PostTask( |
| 1364 FROM_HERE, | 885 FROM_HERE, |
| 1365 base::Bind(callback, FILE_ERROR_IN_USE, base::FilePath())); | 886 base::Bind(callback, FILE_ERROR_IN_USE, base::FilePath())); |
| 1366 return; | 887 return; |
| 1367 } | 888 } |
| 1368 open_files_.insert(file_path); | 889 open_files_.insert(file_path); |
| 1369 | 890 |
| 1370 resource_metadata_->GetResourceEntryByPathOnUIThread( | 891 operations_.EnsureFileDownloaded( |
| 1371 file_path, | 892 file_path, |
| 1372 base::Bind(&FileSystem::OnGetResourceEntryCompleteForOpenFile, | 893 DriveClientContext(USER_INITIATED), |
| 894 GetFileContentInitializedCallback(), |
| 895 google_apis::GetContentCallback(), |
| 896 base::Bind(&FileSystem::OpenFileAfterFileDownloaded, |
| 1373 weak_ptr_factory_.GetWeakPtr(), | 897 weak_ptr_factory_.GetWeakPtr(), |
| 1374 file_path, | 898 file_path, |
| 1375 base::Bind(&FileSystem::OnOpenFileFinished, | 899 base::Bind(&FileSystem::OnOpenFileFinished, |
| 1376 weak_ptr_factory_.GetWeakPtr(), | 900 weak_ptr_factory_.GetWeakPtr(), |
| 1377 file_path, | 901 file_path, |
| 1378 callback))); | 902 callback))); |
| 1379 } | 903 } |
| 1380 | 904 |
| 1381 void FileSystem::OnGetResourceEntryCompleteForOpenFile( | 905 void FileSystem::OpenFileAfterFileDownloaded( |
| 1382 const base::FilePath& file_path, | 906 const base::FilePath& file_path, |
| 1383 const OpenFileCallback& callback, | 907 const OpenFileCallback& callback, |
| 1384 FileError error, | 908 FileError error, |
| 909 const base::FilePath& local_file_path, |
| 1385 scoped_ptr<ResourceEntry> entry) { | 910 scoped_ptr<ResourceEntry> entry) { |
| 1386 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 911 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 1387 DCHECK(!callback.is_null()); | 912 DCHECK(!callback.is_null()); |
| 1388 DCHECK(entry.get() || error != FILE_ERROR_OK); | |
| 1389 | |
| 1390 if (entry.get() && !entry->has_file_specific_info()) | |
| 1391 error = FILE_ERROR_NOT_FOUND; | |
| 1392 | 913 |
| 1393 if (error == FILE_ERROR_OK) { | 914 if (error == FILE_ERROR_OK) { |
| 1394 if (entry->file_specific_info().file_md5().empty() || | 915 DCHECK(entry); |
| 1395 entry->file_specific_info().is_hosted_document()) { | 916 DCHECK(entry->has_file_specific_info()); |
| 1396 // No support for opening a directory or hosted document. | 917 if (entry->file_specific_info().is_hosted_document()) |
| 918 // No support for opening a hosted document. |
| 1397 error = FILE_ERROR_INVALID_OPERATION; | 919 error = FILE_ERROR_INVALID_OPERATION; |
| 1398 } | |
| 1399 } | 920 } |
| 1400 | 921 |
| 1401 if (error != FILE_ERROR_OK) { | 922 if (error != FILE_ERROR_OK) { |
| 1402 callback.Run(error, base::FilePath()); | 923 callback.Run(error, base::FilePath()); |
| 1403 return; | 924 return; |
| 1404 } | 925 } |
| 1405 | 926 |
| 1406 DCHECK(!entry->resource_id().empty()); | 927 cache_->MarkDirtyOnUIThread( |
| 1407 // Extract a pointer before we call Pass() so we can use it below. | 928 entry->resource_id(), |
| 1408 ResourceEntry* entry_ptr = entry.get(); | 929 entry->file_specific_info().file_md5(), |
| 1409 GetResolvedFileByPath( | 930 base::Bind(&FileSystem::OpenFileAfterMarkDirty, |
| 1410 make_scoped_ptr(new GetResolvedFileParams( | 931 weak_ptr_factory_.GetWeakPtr(), |
| 1411 file_path, | 932 entry->resource_id(), |
| 1412 DriveClientContext(USER_INITIATED), | 933 entry->file_specific_info().file_md5(), |
| 1413 entry.Pass(), | 934 callback)); |
| 1414 GetFileContentInitializedCallback(), | |
| 1415 base::Bind(&FileSystem::OnGetFileCompleteForOpenFile, | |
| 1416 weak_ptr_factory_.GetWeakPtr(), | |
| 1417 GetFileCompleteForOpenParams( | |
| 1418 callback, | |
| 1419 entry_ptr->resource_id(), | |
| 1420 entry_ptr->file_specific_info().file_md5())), | |
| 1421 google_apis::GetContentCallback()))); | |
| 1422 } | 935 } |
| 1423 | 936 |
| 1424 void FileSystem::OnGetFileCompleteForOpenFile( | 937 void FileSystem::OpenFileAfterMarkDirty( |
| 1425 const GetFileCompleteForOpenParams& params, | 938 const std::string& resource_id, |
| 1426 FileError error, | 939 const std::string& md5, |
| 1427 const base::FilePath& file_path, | 940 const OpenFileCallback& callback, |
| 1428 scoped_ptr<ResourceEntry> entry) { | 941 FileError error) { |
| 1429 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 942 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 1430 DCHECK(!params.callback.is_null()); | 943 DCHECK(!callback.is_null()); |
| 1431 | 944 |
| 1432 if (error != FILE_ERROR_OK) { | 945 if (error != FILE_ERROR_OK) { |
| 1433 params.callback.Run(error, base::FilePath()); | 946 callback.Run(error, base::FilePath()); |
| 1434 return; | 947 return; |
| 1435 } | 948 } |
| 1436 | 949 |
| 1437 // OpenFile ensures that the file is a regular file. | 950 cache_->GetFileOnUIThread(resource_id, md5, callback); |
| 1438 DCHECK(entry && !entry->file_specific_info().is_hosted_document()); | |
| 1439 | |
| 1440 cache_->MarkDirtyOnUIThread( | |
| 1441 params.resource_id, | |
| 1442 params.md5, | |
| 1443 base::Bind(&FileSystem::OnMarkDirtyInCacheCompleteForOpenFile, | |
| 1444 weak_ptr_factory_.GetWeakPtr(), | |
| 1445 params)); | |
| 1446 } | |
| 1447 | |
| 1448 void FileSystem::OnMarkDirtyInCacheCompleteForOpenFile( | |
| 1449 const GetFileCompleteForOpenParams& params, | |
| 1450 FileError error) { | |
| 1451 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 1452 DCHECK(!params.callback.is_null()); | |
| 1453 | |
| 1454 if (error != FILE_ERROR_OK) { | |
| 1455 params.callback.Run(error, base::FilePath()); | |
| 1456 return; | |
| 1457 } | |
| 1458 | |
| 1459 cache_->GetFileOnUIThread(params.resource_id, params.md5, params.callback); | |
| 1460 } | 951 } |
| 1461 | 952 |
| 1462 void FileSystem::OnOpenFileFinished( | 953 void FileSystem::OnOpenFileFinished( |
| 1463 const base::FilePath& file_path, | 954 const base::FilePath& file_path, |
| 1464 const OpenFileCallback& callback, | 955 const OpenFileCallback& callback, |
| 1465 FileError result, | 956 FileError result, |
| 1466 const base::FilePath& cache_file_path) { | 957 const base::FilePath& cache_file_path) { |
| 1467 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 958 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 1468 DCHECK(!callback.is_null()); | 959 DCHECK(!callback.is_null()); |
| 1469 | 960 |
| (...skipping 170 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1640 callback.Run(FILE_ERROR_NOT_FOUND, scoped_ptr<ResourceEntry>()); | 1131 callback.Run(FILE_ERROR_NOT_FOUND, scoped_ptr<ResourceEntry>()); |
| 1641 return; | 1132 return; |
| 1642 } | 1133 } |
| 1643 | 1134 |
| 1644 PlatformFileInfoProto entry_file_info; | 1135 PlatformFileInfoProto entry_file_info; |
| 1645 util::ConvertPlatformFileInfoToResourceEntry(*file_info, &entry_file_info); | 1136 util::ConvertPlatformFileInfoToResourceEntry(*file_info, &entry_file_info); |
| 1646 *entry->mutable_file_info() = entry_file_info; | 1137 *entry->mutable_file_info() = entry_file_info; |
| 1647 callback.Run(FILE_ERROR_OK, entry.Pass()); | 1138 callback.Run(FILE_ERROR_OK, entry.Pass()); |
| 1648 } | 1139 } |
| 1649 | 1140 |
| 1650 void FileSystem::CancelJobInScheduler(JobID id) { | |
| 1651 scheduler_->CancelJob(id); | |
| 1652 } | |
| 1653 | |
| 1654 } // namespace drive | 1141 } // namespace drive |
| OLD | NEW |