Upstream version 5.34.104.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / chromeos / drive / file_system.cc
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/platform_file.h"
10 #include "base/prefs/pref_service.h"
11 #include "chrome/browser/chromeos/drive/change_list_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   FileCacheEntry cache_entry;
66   if (!cache->GetCacheEntry(local_id, &cache_entry))
67     return FILE_ERROR_OK;
68
69   // When cache is non-dirty and obsolete (old hash), use the original entry.
70   if (!cache_entry.is_dirty() &&
71       entry->file_specific_info().md5() != cache_entry.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   // TODO(hashimoto): crbug.com/346625. Also reflect timestamps.
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 // Used to implement GetCacheEntry.
157 bool GetCacheEntryInternal(internal::ResourceMetadata* resource_metadata,
158                                  internal::FileCache* cache,
159                                  const base::FilePath& drive_file_path,
160                                  FileCacheEntry* cache_entry) {
161   std::string id;
162   if (resource_metadata->GetIdByPath(drive_file_path, &id) != FILE_ERROR_OK)
163     return false;
164
165   return cache->GetCacheEntry(id, cache_entry);
166 }
167
168 // Runs the callback with arguments.
169 void RunGetCacheEntryCallback(const GetCacheEntryCallback& callback,
170                               const FileCacheEntry* cache_entry,
171                               bool success) {
172   DCHECK(!callback.is_null());
173   callback.Run(success, *cache_entry);
174 }
175
176 // Callback for ResourceMetadata::GetLargestChangestamp.
177 // |callback| must not be null.
178 void OnGetLargestChangestamp(
179     FileSystemMetadata metadata,  // Will be modified.
180     const GetFilesystemMetadataCallback& callback,
181     int64 largest_changestamp) {
182   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
183   DCHECK(!callback.is_null());
184
185   metadata.largest_changestamp = largest_changestamp;
186   callback.Run(metadata);
187 }
188
189 // Thin adapter to map GetFileCallback to FileOperationCallback.
190 void GetFileCallbackToFileOperationCallbackAdapter(
191     const FileOperationCallback& callback,
192     FileError error,
193     const base::FilePath& unused_file_path,
194     scoped_ptr<ResourceEntry> unused_entry) {
195   callback.Run(error);
196 }
197
198 // Clears |resource_metadata| and |cache|.
199 FileError ResetOnBlockingPool(internal::ResourceMetadata* resource_metadata,
200                               internal::FileCache* cache) {
201   FileError error = resource_metadata->Reset();
202   if (error != FILE_ERROR_OK)
203     return error;
204  return cache->ClearAll() ? FILE_ERROR_OK : FILE_ERROR_FAILED;
205 }
206
207 }  // namespace
208
209 FileSystem::FileSystem(
210     PrefService* pref_service,
211     EventLogger* logger,
212     internal::FileCache* cache,
213     DriveServiceInterface* drive_service,
214     JobScheduler* scheduler,
215     internal::ResourceMetadata* resource_metadata,
216     base::SequencedTaskRunner* blocking_task_runner,
217     const base::FilePath& temporary_file_directory)
218     : pref_service_(pref_service),
219       logger_(logger),
220       cache_(cache),
221       drive_service_(drive_service),
222       scheduler_(scheduler),
223       resource_metadata_(resource_metadata),
224       last_update_check_error_(FILE_ERROR_OK),
225       blocking_task_runner_(blocking_task_runner),
226       temporary_file_directory_(temporary_file_directory),
227       weak_ptr_factory_(this) {
228   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
229
230   ResetComponents();
231 }
232
233 FileSystem::~FileSystem() {
234   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
235
236   change_list_loader_->RemoveObserver(this);
237 }
238
239 void FileSystem::Reset(const FileOperationCallback& callback) {
240   // Discard the current loader and operation objects and renew them. This is to
241   // avoid that changes initiated before the metadata reset is applied after the
242   // reset, which may cause an inconsistent state.
243   // TODO(kinaba): callbacks held in the subcomponents are discarded. We might
244   // want to have a way to abort and flush callbacks in in-flight operations.
245   ResetComponents();
246
247   base::PostTaskAndReplyWithResult(
248       blocking_task_runner_,
249       FROM_HERE,
250       base::Bind(&ResetOnBlockingPool, resource_metadata_, cache_),
251       callback);
252 }
253
254 void FileSystem::ResetComponents() {
255   file_system::OperationObserver* observer = this;
256
257   about_resource_loader_.reset(new internal::AboutResourceLoader(scheduler_));
258   loader_controller_.reset(new internal::LoaderController);
259   change_list_loader_.reset(new internal::ChangeListLoader(
260       logger_,
261       blocking_task_runner_.get(),
262       resource_metadata_,
263       scheduler_,
264       drive_service_,
265       about_resource_loader_.get(),
266       loader_controller_.get()));
267   change_list_loader_->AddObserver(this);
268
269   sync_client_.reset(new internal::SyncClient(blocking_task_runner_.get(),
270                                               observer,
271                                               scheduler_,
272                                               resource_metadata_,
273                                               cache_,
274                                               loader_controller_.get(),
275                                               temporary_file_directory_));
276
277   copy_operation_.reset(
278       new file_system::CopyOperation(
279           blocking_task_runner_.get(),
280           observer,
281           scheduler_,
282           resource_metadata_,
283           cache_,
284           drive_service_->GetResourceIdCanonicalizer()));
285   create_directory_operation_.reset(new file_system::CreateDirectoryOperation(
286       blocking_task_runner_.get(), observer, resource_metadata_));
287   create_file_operation_.reset(
288       new file_system::CreateFileOperation(blocking_task_runner_.get(),
289                                            observer,
290                                            resource_metadata_));
291   move_operation_.reset(
292       new file_system::MoveOperation(blocking_task_runner_.get(),
293                                      observer,
294                                      resource_metadata_));
295   open_file_operation_.reset(
296       new file_system::OpenFileOperation(blocking_task_runner_.get(),
297                                          observer,
298                                          scheduler_,
299                                          resource_metadata_,
300                                          cache_,
301                                          temporary_file_directory_));
302   remove_operation_.reset(
303       new file_system::RemoveOperation(blocking_task_runner_.get(),
304                                        observer,
305                                        resource_metadata_,
306                                        cache_));
307   touch_operation_.reset(new file_system::TouchOperation(
308       blocking_task_runner_.get(), observer, resource_metadata_));
309   truncate_operation_.reset(
310       new file_system::TruncateOperation(blocking_task_runner_.get(),
311                                          observer,
312                                          scheduler_,
313                                          resource_metadata_,
314                                          cache_,
315                                          temporary_file_directory_));
316   download_operation_.reset(
317       new file_system::DownloadOperation(blocking_task_runner_.get(),
318                                          observer,
319                                          scheduler_,
320                                          resource_metadata_,
321                                          cache_,
322                                          temporary_file_directory_));
323   search_operation_.reset(new file_system::SearchOperation(
324       blocking_task_runner_.get(), scheduler_, resource_metadata_,
325       loader_controller_.get()));
326   get_file_for_saving_operation_.reset(
327       new file_system::GetFileForSavingOperation(logger_,
328                                                  blocking_task_runner_.get(),
329                                                  observer,
330                                                  scheduler_,
331                                                  resource_metadata_,
332                                                  cache_,
333                                                  temporary_file_directory_));
334 }
335
336 void FileSystem::CheckForUpdates() {
337   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
338   DVLOG(1) << "CheckForUpdates";
339
340   change_list_loader_->CheckForUpdates(
341       base::Bind(&FileSystem::OnUpdateChecked, weak_ptr_factory_.GetWeakPtr()));
342 }
343
344 void FileSystem::OnUpdateChecked(FileError error) {
345   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
346   DVLOG(1) << "CheckForUpdates finished: " << FileErrorToString(error);
347   last_update_check_time_ = base::Time::Now();
348   last_update_check_error_ = error;
349 }
350
351 void FileSystem::AddObserver(FileSystemObserver* observer) {
352   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
353   observers_.AddObserver(observer);
354 }
355
356 void FileSystem::RemoveObserver(FileSystemObserver* observer) {
357   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
358   observers_.RemoveObserver(observer);
359 }
360
361 void FileSystem::TransferFileFromLocalToRemote(
362     const base::FilePath& local_src_file_path,
363     const base::FilePath& remote_dest_file_path,
364     const FileOperationCallback& callback) {
365   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
366   DCHECK(!callback.is_null());
367   copy_operation_->TransferFileFromLocalToRemote(local_src_file_path,
368                                                  remote_dest_file_path,
369                                                  callback);
370 }
371
372 void FileSystem::Copy(const base::FilePath& src_file_path,
373                       const base::FilePath& dest_file_path,
374                       bool preserve_last_modified,
375                       const FileOperationCallback& callback) {
376   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
377   DCHECK(!callback.is_null());
378   copy_operation_->Copy(
379       src_file_path, dest_file_path, preserve_last_modified, callback);
380 }
381
382 void FileSystem::Move(const base::FilePath& src_file_path,
383                       const base::FilePath& dest_file_path,
384                       bool preserve_last_modified,
385                       const FileOperationCallback& callback) {
386   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
387   DCHECK(!callback.is_null());
388   move_operation_->Move(
389       src_file_path, dest_file_path, preserve_last_modified, callback);
390 }
391
392 void FileSystem::Remove(const base::FilePath& file_path,
393                         bool is_recursive,
394                         const FileOperationCallback& callback) {
395   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
396   DCHECK(!callback.is_null());
397   remove_operation_->Remove(file_path, is_recursive, callback);
398 }
399
400 void FileSystem::CreateDirectory(
401     const base::FilePath& directory_path,
402     bool is_exclusive,
403     bool is_recursive,
404     const FileOperationCallback& callback) {
405   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
406   DCHECK(!callback.is_null());
407
408   // Ensure its parent directory is loaded to the local metadata.
409   change_list_loader_->LoadDirectoryIfNeeded(
410       directory_path.DirName(),
411       base::Bind(&FileSystem::CreateDirectoryAfterLoad,
412                  weak_ptr_factory_.GetWeakPtr(),
413                  directory_path, is_exclusive, is_recursive, callback));
414 }
415
416 void FileSystem::CreateDirectoryAfterLoad(
417     const base::FilePath& directory_path,
418     bool is_exclusive,
419     bool is_recursive,
420     const FileOperationCallback& callback,
421     FileError load_error) {
422   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
423   DCHECK(!callback.is_null());
424
425   DVLOG_IF(1, load_error != FILE_ERROR_OK) << "LoadDirectoryIfNeeded failed. "
426                                            << FileErrorToString(load_error);
427
428   create_directory_operation_->CreateDirectory(
429       directory_path, is_exclusive, is_recursive, callback);
430 }
431
432 void FileSystem::CreateFile(const base::FilePath& file_path,
433                             bool is_exclusive,
434                             const std::string& mime_type,
435                             const FileOperationCallback& callback) {
436   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
437   DCHECK(!callback.is_null());
438   create_file_operation_->CreateFile(
439       file_path, is_exclusive, mime_type, callback);
440 }
441
442 void FileSystem::TouchFile(const base::FilePath& file_path,
443                            const base::Time& last_access_time,
444                            const base::Time& last_modified_time,
445                            const FileOperationCallback& callback) {
446   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
447   DCHECK(!last_access_time.is_null());
448   DCHECK(!last_modified_time.is_null());
449   DCHECK(!callback.is_null());
450   touch_operation_->TouchFile(
451       file_path, last_access_time, last_modified_time, callback);
452 }
453
454 void FileSystem::TruncateFile(const base::FilePath& file_path,
455                               int64 length,
456                               const FileOperationCallback& callback) {
457   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
458   DCHECK(!callback.is_null());
459   truncate_operation_->Truncate(file_path, length, callback);
460 }
461
462 void FileSystem::Pin(const base::FilePath& file_path,
463                      const FileOperationCallback& callback) {
464   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
465   DCHECK(!callback.is_null());
466
467   std::string* local_id = new std::string;
468   base::PostTaskAndReplyWithResult(
469       blocking_task_runner_,
470       FROM_HERE,
471       base::Bind(&PinInternal, resource_metadata_, cache_, file_path, local_id),
472       base::Bind(&FileSystem::FinishPin,
473                  weak_ptr_factory_.GetWeakPtr(),
474                  callback,
475                  base::Owned(local_id)));
476 }
477
478 void FileSystem::FinishPin(const FileOperationCallback& callback,
479                            const std::string* local_id,
480                            FileError error) {
481   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
482   DCHECK(!callback.is_null());
483
484   if (error == FILE_ERROR_OK)
485     sync_client_->AddFetchTask(*local_id);
486   callback.Run(error);
487 }
488
489 void FileSystem::Unpin(const base::FilePath& file_path,
490                        const FileOperationCallback& callback) {
491   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
492   DCHECK(!callback.is_null());
493
494   std::string* local_id = new std::string;
495   base::PostTaskAndReplyWithResult(
496       blocking_task_runner_,
497       FROM_HERE,
498       base::Bind(&UnpinInternal,
499                  resource_metadata_,
500                  cache_,
501                  file_path,
502                  local_id),
503       base::Bind(&FileSystem::FinishUnpin,
504                  weak_ptr_factory_.GetWeakPtr(),
505                  callback,
506                  base::Owned(local_id)));
507 }
508
509 void FileSystem::FinishUnpin(const FileOperationCallback& callback,
510                              const std::string* local_id,
511                              FileError error) {
512   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
513   DCHECK(!callback.is_null());
514
515   if (error == FILE_ERROR_OK)
516     sync_client_->RemoveFetchTask(*local_id);
517   callback.Run(error);
518 }
519
520 void FileSystem::GetFile(const base::FilePath& file_path,
521                          const GetFileCallback& callback) {
522   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
523   DCHECK(!callback.is_null());
524
525   download_operation_->EnsureFileDownloadedByPath(
526       file_path,
527       ClientContext(USER_INITIATED),
528       GetFileContentInitializedCallback(),
529       google_apis::GetContentCallback(),
530       callback);
531 }
532
533 void FileSystem::GetFileForSaving(const base::FilePath& file_path,
534                                   const GetFileCallback& callback) {
535   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
536   DCHECK(!callback.is_null());
537
538   get_file_for_saving_operation_->GetFileForSaving(file_path, callback);
539 }
540
541 void FileSystem::GetFileContent(
542     const base::FilePath& file_path,
543     const GetFileContentInitializedCallback& initialized_callback,
544     const google_apis::GetContentCallback& get_content_callback,
545     const FileOperationCallback& completion_callback) {
546   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
547   DCHECK(!initialized_callback.is_null());
548   DCHECK(!get_content_callback.is_null());
549   DCHECK(!completion_callback.is_null());
550
551   download_operation_->EnsureFileDownloadedByPath(
552       file_path,
553       ClientContext(USER_INITIATED),
554       initialized_callback,
555       get_content_callback,
556       base::Bind(&GetFileCallbackToFileOperationCallbackAdapter,
557                  completion_callback));
558 }
559
560 void FileSystem::GetResourceEntry(
561     const base::FilePath& file_path,
562     const GetResourceEntryCallback& callback) {
563   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
564   DCHECK(!callback.is_null());
565
566   change_list_loader_->LoadDirectoryIfNeeded(
567       file_path.DirName(),
568       base::Bind(&FileSystem::GetResourceEntryAfterLoad,
569                  weak_ptr_factory_.GetWeakPtr(),
570                  file_path,
571                  callback));
572 }
573
574 void FileSystem::GetResourceEntryAfterLoad(
575     const base::FilePath& file_path,
576     const GetResourceEntryCallback& callback,
577     FileError error) {
578   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
579   DCHECK(!callback.is_null());
580
581   DVLOG_IF(1, error != FILE_ERROR_OK) << "LoadDirectoryIfNeeded failed. "
582                                       << FileErrorToString(error);
583
584   scoped_ptr<ResourceEntry> entry(new ResourceEntry);
585   ResourceEntry* entry_ptr = entry.get();
586   base::PostTaskAndReplyWithResult(
587       blocking_task_runner_,
588       FROM_HERE,
589       base::Bind(&GetLocallyStoredResourceEntry,
590                  resource_metadata_,
591                  cache_,
592                  file_path,
593                  entry_ptr),
594       base::Bind(&RunGetResourceEntryCallback, callback, base::Passed(&entry)));
595 }
596
597 void FileSystem::ReadDirectory(
598     const base::FilePath& directory_path,
599     const ReadDirectoryCallback& callback) {
600   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
601   DCHECK(!callback.is_null());
602
603   change_list_loader_->LoadDirectoryIfNeeded(
604       directory_path,
605       base::Bind(&FileSystem::ReadDirectoryAfterLoad,
606                  weak_ptr_factory_.GetWeakPtr(),
607                  directory_path,
608                  callback));
609 }
610
611 void FileSystem::ReadDirectoryAfterLoad(
612     const base::FilePath& directory_path,
613     const ReadDirectoryCallback& callback,
614     FileError error) {
615   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
616   DCHECK(!callback.is_null());
617
618   DVLOG_IF(1, error != FILE_ERROR_OK) << "LoadDirectoryIfNeeded failed. "
619                                       << FileErrorToString(error);
620
621   ResourceEntryVector* entries = new ResourceEntryVector;
622   base::PostTaskAndReplyWithResult(
623       blocking_task_runner_.get(),
624       FROM_HERE,
625       base::Bind(&internal::ResourceMetadata::ReadDirectoryByPath,
626                  base::Unretained(resource_metadata_),
627                  directory_path,
628                  entries),
629       base::Bind(&FileSystem::ReadDirectoryAfterRead,
630                  weak_ptr_factory_.GetWeakPtr(),
631                  directory_path,
632                  callback,
633                  base::Owned(entries)));
634 }
635
636 void FileSystem::ReadDirectoryAfterRead(const base::FilePath& directory_path,
637                                         const ReadDirectoryCallback& callback,
638                                         const ResourceEntryVector* entries,
639                                         FileError error) {
640   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
641   DCHECK(!callback.is_null());
642
643   if (error != FILE_ERROR_OK) {
644     callback.Run(error, scoped_ptr<ResourceEntryVector>(), false);
645     return;
646   }
647
648   // TODO(satorux): Stop handling hide_hosted_docs here. crbug.com/256520.
649   const bool hide_hosted_docs =
650       pref_service_->GetBoolean(prefs::kDisableDriveHostedFiles);
651   scoped_ptr<ResourceEntryVector> filtered(new ResourceEntryVector);
652   for (size_t i = 0; i < entries->size(); ++i) {
653     if (hide_hosted_docs &&
654         entries->at(i).file_specific_info().is_hosted_document()) {
655       continue;
656     }
657     filtered->push_back(entries->at(i));
658   }
659
660   callback.Run(FILE_ERROR_OK, filtered.Pass(), false);
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(
694     const base::FilePath& file_path,
695     const GURL& embed_origin,
696     const GetShareUrlCallback& callback) {
697   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
698   DCHECK(!callback.is_null());
699
700   // Resolve the resource id.
701   resource_metadata_->GetResourceEntryByPathOnUIThread(
702       file_path,
703       base::Bind(&FileSystem::GetShareUrlAfterGetResourceEntry,
704                  weak_ptr_factory_.GetWeakPtr(),
705                  file_path,
706                  embed_origin,
707                  callback));
708 }
709
710 void FileSystem::GetShareUrlAfterGetResourceEntry(
711     const base::FilePath& file_path,
712     const GURL& embed_origin,
713     const GetShareUrlCallback& callback,
714     FileError error,
715     scoped_ptr<ResourceEntry> entry) {
716   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
717   DCHECK(!callback.is_null());
718
719   if (error != FILE_ERROR_OK) {
720     callback.Run(error, GURL());
721     return;
722   }
723   if (entry->resource_id().empty()) {
724     // This entry does not exist on the server. Just return.
725     callback.Run(FILE_ERROR_FAILED, GURL());
726     return;
727   }
728
729   scheduler_->GetShareUrl(
730       entry->resource_id(),
731       embed_origin,
732       ClientContext(USER_INITIATED),
733       base::Bind(&FileSystem::OnGetResourceEntryForGetShareUrl,
734                  weak_ptr_factory_.GetWeakPtr(),
735                  callback));
736 }
737
738 void FileSystem::OnGetResourceEntryForGetShareUrl(
739     const GetShareUrlCallback& callback,
740     google_apis::GDataErrorCode status,
741     const GURL& share_url) {
742   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
743   DCHECK(!callback.is_null());
744
745   FileError error = GDataToFileError(status);
746   if (error != FILE_ERROR_OK) {
747     callback.Run(error, GURL());
748     return;
749   }
750
751   if (share_url.is_empty()) {
752     callback.Run(FILE_ERROR_FAILED, GURL());
753     return;
754   }
755
756   callback.Run(FILE_ERROR_OK, share_url);
757 }
758
759 void FileSystem::Search(const std::string& search_query,
760                         const GURL& next_link,
761                         const SearchCallback& callback) {
762   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
763   DCHECK(!callback.is_null());
764   search_operation_->Search(search_query, next_link, callback);
765 }
766
767 void FileSystem::SearchMetadata(const std::string& query,
768                                 int options,
769                                 int at_most_num_matches,
770                                 const SearchMetadataCallback& callback) {
771   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
772
773   // TODO(satorux): Stop handling hide_hosted_docs here. crbug.com/256520.
774   if (pref_service_->GetBoolean(prefs::kDisableDriveHostedFiles))
775     options |= SEARCH_METADATA_EXCLUDE_HOSTED_DOCUMENTS;
776
777   drive::internal::SearchMetadata(blocking_task_runner_,
778                                   resource_metadata_,
779                                   query,
780                                   options,
781                                   at_most_num_matches,
782                                   callback);
783 }
784
785 void FileSystem::OnDirectoryChangedByOperation(
786     const base::FilePath& directory_path) {
787   OnDirectoryChanged(directory_path);
788 }
789
790 void FileSystem::OnEntryUpdatedByOperation(const std::string& local_id) {
791   sync_client_->AddUpdateTask(ClientContext(USER_INITIATED), local_id);
792 }
793
794 void FileSystem::OnDriveSyncError(file_system::DriveSyncErrorType type,
795                                   const std::string& local_id) {
796   base::PostTaskAndReplyWithResult(
797       blocking_task_runner_,
798       FROM_HERE,
799       base::Bind(&internal::ResourceMetadata::GetFilePath,
800                  base::Unretained(resource_metadata_),
801                  local_id),
802       base::Bind(&FileSystem::OnDriveSyncErrorAfterGetFilePath,
803                  weak_ptr_factory_.GetWeakPtr(),
804                  type));
805 }
806
807 void FileSystem::OnDriveSyncErrorAfterGetFilePath(
808     file_system::DriveSyncErrorType type,
809     const base::FilePath& path) {
810   if (path.empty())
811     return;
812   FOR_EACH_OBSERVER(FileSystemObserver,
813                     observers_,
814                     OnDriveSyncError(type, path));
815 }
816
817 void FileSystem::OnDirectoryChanged(const base::FilePath& directory_path) {
818   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
819
820   FOR_EACH_OBSERVER(FileSystemObserver, observers_,
821                     OnDirectoryChanged(directory_path));
822 }
823
824 void FileSystem::OnLoadFromServerComplete() {
825   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
826
827   sync_client_->StartCheckingExistingPinnedFiles();
828 }
829
830 void FileSystem::OnInitialLoadComplete() {
831   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
832
833   blocking_task_runner_->PostTask(FROM_HERE,
834                                   base::Bind(&internal::RemoveStaleCacheFiles,
835                                              cache_,
836                                              resource_metadata_));
837   sync_client_->StartProcessingBacklog();
838 }
839
840 void FileSystem::GetMetadata(
841     const GetFilesystemMetadataCallback& callback) {
842   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
843   DCHECK(!callback.is_null());
844
845   FileSystemMetadata metadata;
846   metadata.refreshing = change_list_loader_->IsRefreshing();
847
848   // Metadata related to delta update.
849   metadata.last_update_check_time = last_update_check_time_;
850   metadata.last_update_check_error = last_update_check_error_;
851
852   base::PostTaskAndReplyWithResult(
853       blocking_task_runner_,
854       FROM_HERE,
855       base::Bind(&internal::ResourceMetadata::GetLargestChangestamp,
856                  base::Unretained(resource_metadata_)),
857       base::Bind(&OnGetLargestChangestamp, metadata, callback));
858 }
859
860 void FileSystem::MarkCacheFileAsMounted(
861     const base::FilePath& drive_file_path,
862     const MarkMountedCallback& callback) {
863   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
864   DCHECK(!callback.is_null());
865
866   base::FilePath* cache_file_path = new base::FilePath;
867   base::PostTaskAndReplyWithResult(
868       blocking_task_runner_,
869       FROM_HERE,
870       base::Bind(&MarkCacheFileAsMountedInternal,
871                  resource_metadata_,
872                  cache_,
873                  drive_file_path,
874                  cache_file_path),
875       base::Bind(&RunMarkMountedCallback,
876                  callback,
877                  base::Owned(cache_file_path)));
878 }
879
880 void FileSystem::MarkCacheFileAsUnmounted(
881     const base::FilePath& cache_file_path,
882     const FileOperationCallback& callback) {
883   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
884   DCHECK(!callback.is_null());
885
886   if (!cache_->IsUnderFileCacheDirectory(cache_file_path)) {
887     callback.Run(FILE_ERROR_FAILED);
888     return;
889   }
890
891   base::PostTaskAndReplyWithResult(
892       blocking_task_runner_,
893       FROM_HERE,
894       base::Bind(&internal::FileCache::MarkAsUnmounted,
895                  base::Unretained(cache_),
896                  cache_file_path),
897       callback);
898 }
899
900 void FileSystem::GetCacheEntry(
901     const base::FilePath& drive_file_path,
902     const GetCacheEntryCallback& callback) {
903   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
904   DCHECK(!callback.is_null());
905
906   FileCacheEntry* cache_entry = new FileCacheEntry;
907   base::PostTaskAndReplyWithResult(
908       blocking_task_runner_,
909       FROM_HERE,
910       base::Bind(&GetCacheEntryInternal,
911                  resource_metadata_,
912                  cache_,
913                  drive_file_path,
914                  cache_entry),
915       base::Bind(&RunGetCacheEntryCallback,
916                  callback,
917                  base::Owned(cache_entry)));
918 }
919
920 void FileSystem::OpenFile(const base::FilePath& file_path,
921                           OpenMode open_mode,
922                           const std::string& mime_type,
923                           const OpenFileCallback& callback) {
924   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
925   DCHECK(!callback.is_null());
926
927   open_file_operation_->OpenFile(file_path, open_mode, mime_type, callback);
928 }
929
930 }  // namespace drive