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