Home | History | Annotate | Download | only in drive
      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