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