Upstream version 7.35.139.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       drive_service_,
334       about_resource_loader_.get(),
335       loader_controller_.get()));
336   directory_loader_->AddObserver(this);
337
338   sync_client_.reset(new internal::SyncClient(blocking_task_runner_.get(),
339                                               observer,
340                                               scheduler_,
341                                               resource_metadata_,
342                                               cache_,
343                                               loader_controller_.get(),
344                                               temporary_file_directory_));
345
346   copy_operation_.reset(
347       new file_system::CopyOperation(
348           blocking_task_runner_.get(),
349           observer,
350           scheduler_,
351           resource_metadata_,
352           cache_,
353           drive_service_->GetResourceIdCanonicalizer()));
354   create_directory_operation_.reset(new file_system::CreateDirectoryOperation(
355       blocking_task_runner_.get(), observer, resource_metadata_));
356   create_file_operation_.reset(
357       new file_system::CreateFileOperation(blocking_task_runner_.get(),
358                                            observer,
359                                            resource_metadata_));
360   move_operation_.reset(
361       new file_system::MoveOperation(blocking_task_runner_.get(),
362                                      observer,
363                                      resource_metadata_));
364   open_file_operation_.reset(
365       new file_system::OpenFileOperation(blocking_task_runner_.get(),
366                                          observer,
367                                          scheduler_,
368                                          resource_metadata_,
369                                          cache_,
370                                          temporary_file_directory_));
371   remove_operation_.reset(
372       new file_system::RemoveOperation(blocking_task_runner_.get(),
373                                        observer,
374                                        resource_metadata_,
375                                        cache_));
376   touch_operation_.reset(new file_system::TouchOperation(
377       blocking_task_runner_.get(), observer, resource_metadata_));
378   truncate_operation_.reset(
379       new file_system::TruncateOperation(blocking_task_runner_.get(),
380                                          observer,
381                                          scheduler_,
382                                          resource_metadata_,
383                                          cache_,
384                                          temporary_file_directory_));
385   download_operation_.reset(
386       new file_system::DownloadOperation(blocking_task_runner_.get(),
387                                          observer,
388                                          scheduler_,
389                                          resource_metadata_,
390                                          cache_,
391                                          temporary_file_directory_));
392   search_operation_.reset(new file_system::SearchOperation(
393       blocking_task_runner_.get(), scheduler_, resource_metadata_,
394       loader_controller_.get()));
395   get_file_for_saving_operation_.reset(
396       new file_system::GetFileForSavingOperation(logger_,
397                                                  blocking_task_runner_.get(),
398                                                  observer,
399                                                  scheduler_,
400                                                  resource_metadata_,
401                                                  cache_,
402                                                  temporary_file_directory_));
403 }
404
405 void FileSystem::CheckForUpdates() {
406   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
407   DVLOG(1) << "CheckForUpdates";
408
409   change_list_loader_->CheckForUpdates(
410       base::Bind(&FileSystem::OnUpdateChecked, weak_ptr_factory_.GetWeakPtr()));
411 }
412
413 void FileSystem::OnUpdateChecked(FileError error) {
414   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
415   DVLOG(1) << "CheckForUpdates finished: " << FileErrorToString(error);
416   last_update_check_time_ = base::Time::Now();
417   last_update_check_error_ = error;
418 }
419
420 void FileSystem::AddObserver(FileSystemObserver* observer) {
421   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
422   observers_.AddObserver(observer);
423 }
424
425 void FileSystem::RemoveObserver(FileSystemObserver* observer) {
426   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
427   observers_.RemoveObserver(observer);
428 }
429
430 void FileSystem::TransferFileFromLocalToRemote(
431     const base::FilePath& local_src_file_path,
432     const base::FilePath& remote_dest_file_path,
433     const FileOperationCallback& callback) {
434   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
435   DCHECK(!callback.is_null());
436   copy_operation_->TransferFileFromLocalToRemote(local_src_file_path,
437                                                  remote_dest_file_path,
438                                                  callback);
439 }
440
441 void FileSystem::Copy(const base::FilePath& src_file_path,
442                       const base::FilePath& dest_file_path,
443                       bool preserve_last_modified,
444                       const FileOperationCallback& callback) {
445   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
446   DCHECK(!callback.is_null());
447   copy_operation_->Copy(
448       src_file_path, dest_file_path, preserve_last_modified, callback);
449 }
450
451 void FileSystem::Move(const base::FilePath& src_file_path,
452                       const base::FilePath& dest_file_path,
453                       const FileOperationCallback& callback) {
454   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
455   DCHECK(!callback.is_null());
456   move_operation_->Move(src_file_path, dest_file_path, callback);
457 }
458
459 void FileSystem::Remove(const base::FilePath& file_path,
460                         bool is_recursive,
461                         const FileOperationCallback& callback) {
462   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
463   DCHECK(!callback.is_null());
464   remove_operation_->Remove(file_path, is_recursive, callback);
465 }
466
467 void FileSystem::CreateDirectory(
468     const base::FilePath& directory_path,
469     bool is_exclusive,
470     bool is_recursive,
471     const FileOperationCallback& callback) {
472   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
473   DCHECK(!callback.is_null());
474
475   CreateDirectoryParams params;
476   params.directory_path = directory_path;
477   params.is_exclusive = is_exclusive;
478   params.is_recursive = is_recursive;
479   params.callback = callback;
480
481   // Ensure its parent directory is loaded to the local metadata.
482   ReadDirectory(directory_path.DirName(),
483                 ReadDirectoryEntriesCallback(),
484                 base::Bind(&FileSystem::CreateDirectoryAfterRead,
485                            weak_ptr_factory_.GetWeakPtr(), params));
486 }
487
488 void FileSystem::CreateDirectoryAfterRead(const CreateDirectoryParams& params,
489                                           FileError error) {
490   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
491   DCHECK(!params.callback.is_null());
492
493   DVLOG_IF(1, error != FILE_ERROR_OK) << "ReadDirectory failed. "
494                                       << FileErrorToString(error);
495
496   create_directory_operation_->CreateDirectory(
497       params.directory_path, params.is_exclusive, params.is_recursive,
498       params.callback);
499 }
500
501 void FileSystem::CreateFile(const base::FilePath& file_path,
502                             bool is_exclusive,
503                             const std::string& mime_type,
504                             const FileOperationCallback& callback) {
505   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
506   DCHECK(!callback.is_null());
507   create_file_operation_->CreateFile(
508       file_path, is_exclusive, mime_type, callback);
509 }
510
511 void FileSystem::TouchFile(const base::FilePath& file_path,
512                            const base::Time& last_access_time,
513                            const base::Time& last_modified_time,
514                            const FileOperationCallback& callback) {
515   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
516   DCHECK(!callback.is_null());
517   touch_operation_->TouchFile(
518       file_path, last_access_time, last_modified_time, callback);
519 }
520
521 void FileSystem::TruncateFile(const base::FilePath& file_path,
522                               int64 length,
523                               const FileOperationCallback& callback) {
524   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
525   DCHECK(!callback.is_null());
526   truncate_operation_->Truncate(file_path, length, callback);
527 }
528
529 void FileSystem::Pin(const base::FilePath& file_path,
530                      const FileOperationCallback& callback) {
531   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
532   DCHECK(!callback.is_null());
533
534   std::string* local_id = new std::string;
535   base::PostTaskAndReplyWithResult(
536       blocking_task_runner_,
537       FROM_HERE,
538       base::Bind(&PinInternal, resource_metadata_, cache_, file_path, local_id),
539       base::Bind(&FileSystem::FinishPin,
540                  weak_ptr_factory_.GetWeakPtr(),
541                  callback,
542                  base::Owned(local_id)));
543 }
544
545 void FileSystem::FinishPin(const FileOperationCallback& callback,
546                            const std::string* local_id,
547                            FileError error) {
548   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
549   DCHECK(!callback.is_null());
550
551   if (error == FILE_ERROR_OK)
552     sync_client_->AddFetchTask(*local_id);
553   callback.Run(error);
554 }
555
556 void FileSystem::Unpin(const base::FilePath& file_path,
557                        const FileOperationCallback& callback) {
558   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
559   DCHECK(!callback.is_null());
560
561   std::string* local_id = new std::string;
562   base::PostTaskAndReplyWithResult(
563       blocking_task_runner_,
564       FROM_HERE,
565       base::Bind(&UnpinInternal,
566                  resource_metadata_,
567                  cache_,
568                  file_path,
569                  local_id),
570       base::Bind(&FileSystem::FinishUnpin,
571                  weak_ptr_factory_.GetWeakPtr(),
572                  callback,
573                  base::Owned(local_id)));
574 }
575
576 void FileSystem::FinishUnpin(const FileOperationCallback& callback,
577                              const std::string* local_id,
578                              FileError error) {
579   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
580   DCHECK(!callback.is_null());
581
582   if (error == FILE_ERROR_OK)
583     sync_client_->RemoveFetchTask(*local_id);
584   callback.Run(error);
585 }
586
587 void FileSystem::GetFile(const base::FilePath& file_path,
588                          const GetFileCallback& callback) {
589   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
590   DCHECK(!callback.is_null());
591
592   download_operation_->EnsureFileDownloadedByPath(
593       file_path,
594       ClientContext(USER_INITIATED),
595       GetFileContentInitializedCallback(),
596       google_apis::GetContentCallback(),
597       callback);
598 }
599
600 void FileSystem::GetFileForSaving(const base::FilePath& file_path,
601                                   const GetFileCallback& callback) {
602   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
603   DCHECK(!callback.is_null());
604
605   get_file_for_saving_operation_->GetFileForSaving(file_path, callback);
606 }
607
608 base::Closure FileSystem::GetFileContent(
609     const base::FilePath& file_path,
610     const GetFileContentInitializedCallback& initialized_callback,
611     const google_apis::GetContentCallback& get_content_callback,
612     const FileOperationCallback& completion_callback) {
613   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
614   DCHECK(!initialized_callback.is_null());
615   DCHECK(!get_content_callback.is_null());
616   DCHECK(!completion_callback.is_null());
617
618   return download_operation_->EnsureFileDownloadedByPath(
619       file_path,
620       ClientContext(USER_INITIATED),
621       initialized_callback,
622       get_content_callback,
623       base::Bind(&GetFileCallbackToFileOperationCallbackAdapter,
624                  completion_callback));
625 }
626
627 void FileSystem::GetResourceEntry(
628     const base::FilePath& file_path,
629     const GetResourceEntryCallback& callback) {
630   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
631   DCHECK(!callback.is_null());
632
633   ReadDirectory(file_path.DirName(),
634                 ReadDirectoryEntriesCallback(),
635                 base::Bind(&FileSystem::GetResourceEntryAfterRead,
636                            weak_ptr_factory_.GetWeakPtr(),
637                            file_path,
638                            callback));
639 }
640
641 void FileSystem::GetResourceEntryAfterRead(
642     const base::FilePath& file_path,
643     const GetResourceEntryCallback& callback,
644     FileError error) {
645   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
646   DCHECK(!callback.is_null());
647
648   DVLOG_IF(1, error != FILE_ERROR_OK) << "ReadDirectory failed. "
649                                       << FileErrorToString(error);
650
651   scoped_ptr<ResourceEntry> entry(new ResourceEntry);
652   ResourceEntry* entry_ptr = entry.get();
653   base::PostTaskAndReplyWithResult(
654       blocking_task_runner_,
655       FROM_HERE,
656       base::Bind(&GetLocallyStoredResourceEntry,
657                  resource_metadata_,
658                  cache_,
659                  file_path,
660                  entry_ptr),
661       base::Bind(&RunGetResourceEntryCallback, callback, base::Passed(&entry)));
662 }
663
664 void FileSystem::ReadDirectory(
665     const base::FilePath& directory_path,
666     const ReadDirectoryEntriesCallback& entries_callback_in,
667     const FileOperationCallback& completion_callback) {
668   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
669   DCHECK(!completion_callback.is_null());
670
671   const bool hide_hosted_docs =
672       pref_service_->GetBoolean(prefs::kDisableDriveHostedFiles);
673   ReadDirectoryEntriesCallback entries_callback = entries_callback_in;
674   if (!entries_callback.is_null() && hide_hosted_docs)
675     entries_callback = base::Bind(&FilterHostedDocuments, entries_callback);
676
677   directory_loader_->ReadDirectory(
678       directory_path, entries_callback, completion_callback);
679
680   // Also start loading all of the user's contents.
681   change_list_loader_->LoadIfNeeded(
682       base::Bind(&util::EmptyFileOperationCallback));
683 }
684
685 void FileSystem::GetAvailableSpace(
686     const GetAvailableSpaceCallback& callback) {
687   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
688   DCHECK(!callback.is_null());
689
690   about_resource_loader_->GetAboutResource(
691       base::Bind(&FileSystem::OnGetAboutResource,
692                  weak_ptr_factory_.GetWeakPtr(),
693                  callback));
694 }
695
696 void FileSystem::OnGetAboutResource(
697     const GetAvailableSpaceCallback& callback,
698     google_apis::GDataErrorCode status,
699     scoped_ptr<google_apis::AboutResource> about_resource) {
700   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
701   DCHECK(!callback.is_null());
702
703   FileError error = GDataToFileError(status);
704   if (error != FILE_ERROR_OK) {
705     callback.Run(error, -1, -1);
706     return;
707   }
708   DCHECK(about_resource);
709
710   callback.Run(FILE_ERROR_OK,
711                about_resource->quota_bytes_total(),
712                about_resource->quota_bytes_used());
713 }
714
715 void FileSystem::GetShareUrl(const base::FilePath& file_path,
716                              const GURL& embed_origin,
717                              const GetShareUrlCallback& callback) {
718   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
719   DCHECK(!callback.is_null());
720
721   // Resolve the resource id.
722   ResourceEntry* entry = new ResourceEntry;
723   base::PostTaskAndReplyWithResult(
724       blocking_task_runner_.get(),
725       FROM_HERE,
726       base::Bind(&internal::ResourceMetadata::GetResourceEntryByPath,
727                  base::Unretained(resource_metadata_),
728                  file_path,
729                  entry),
730       base::Bind(&FileSystem::GetShareUrlAfterGetResourceEntry,
731                  weak_ptr_factory_.GetWeakPtr(),
732                  file_path,
733                  embed_origin,
734                  callback,
735                  base::Owned(entry)));
736 }
737
738 void FileSystem::GetShareUrlAfterGetResourceEntry(
739     const base::FilePath& file_path,
740     const GURL& embed_origin,
741     const GetShareUrlCallback& callback,
742     ResourceEntry* entry,
743     FileError error) {
744   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
745   DCHECK(!callback.is_null());
746
747   if (error != FILE_ERROR_OK) {
748     callback.Run(error, GURL());
749     return;
750   }
751   if (entry->resource_id().empty()) {
752     // This entry does not exist on the server. Just return.
753     callback.Run(FILE_ERROR_FAILED, GURL());
754     return;
755   }
756
757   scheduler_->GetShareUrl(
758       entry->resource_id(),
759       embed_origin,
760       ClientContext(USER_INITIATED),
761       base::Bind(&FileSystem::OnGetResourceEntryForGetShareUrl,
762                  weak_ptr_factory_.GetWeakPtr(),
763                  callback));
764 }
765
766 void FileSystem::OnGetResourceEntryForGetShareUrl(
767     const GetShareUrlCallback& callback,
768     google_apis::GDataErrorCode status,
769     const GURL& share_url) {
770   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
771   DCHECK(!callback.is_null());
772
773   FileError error = GDataToFileError(status);
774   if (error != FILE_ERROR_OK) {
775     callback.Run(error, GURL());
776     return;
777   }
778
779   if (share_url.is_empty()) {
780     callback.Run(FILE_ERROR_FAILED, GURL());
781     return;
782   }
783
784   callback.Run(FILE_ERROR_OK, share_url);
785 }
786
787 void FileSystem::Search(const std::string& search_query,
788                         const GURL& next_link,
789                         const SearchCallback& callback) {
790   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
791   DCHECK(!callback.is_null());
792   search_operation_->Search(search_query, next_link, callback);
793 }
794
795 void FileSystem::SearchMetadata(const std::string& query,
796                                 int options,
797                                 int at_most_num_matches,
798                                 const SearchMetadataCallback& callback) {
799   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
800
801   // TODO(satorux): Stop handling hide_hosted_docs here. crbug.com/256520.
802   if (pref_service_->GetBoolean(prefs::kDisableDriveHostedFiles))
803     options |= SEARCH_METADATA_EXCLUDE_HOSTED_DOCUMENTS;
804
805   drive::internal::SearchMetadata(blocking_task_runner_,
806                                   resource_metadata_,
807                                   query,
808                                   options,
809                                   at_most_num_matches,
810                                   callback);
811 }
812
813 void FileSystem::OnDirectoryChangedByOperation(
814     const base::FilePath& directory_path) {
815   OnDirectoryChanged(directory_path);
816 }
817
818 void FileSystem::OnEntryUpdatedByOperation(const std::string& local_id) {
819   sync_client_->AddUpdateTask(ClientContext(USER_INITIATED), local_id);
820 }
821
822 void FileSystem::OnDriveSyncError(file_system::DriveSyncErrorType type,
823                                   const std::string& local_id) {
824   base::PostTaskAndReplyWithResult(
825       blocking_task_runner_,
826       FROM_HERE,
827       base::Bind(&internal::ResourceMetadata::GetFilePath,
828                  base::Unretained(resource_metadata_),
829                  local_id),
830       base::Bind(&FileSystem::OnDriveSyncErrorAfterGetFilePath,
831                  weak_ptr_factory_.GetWeakPtr(),
832                  type));
833 }
834
835 void FileSystem::OnDriveSyncErrorAfterGetFilePath(
836     file_system::DriveSyncErrorType type,
837     const base::FilePath& path) {
838   if (path.empty())
839     return;
840   FOR_EACH_OBSERVER(FileSystemObserver,
841                     observers_,
842                     OnDriveSyncError(type, path));
843 }
844
845 void FileSystem::OnDirectoryChanged(const base::FilePath& directory_path) {
846   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
847
848   FOR_EACH_OBSERVER(FileSystemObserver, observers_,
849                     OnDirectoryChanged(directory_path));
850 }
851
852 void FileSystem::OnLoadFromServerComplete() {
853   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
854
855   sync_client_->StartCheckingExistingPinnedFiles();
856 }
857
858 void FileSystem::OnInitialLoadComplete() {
859   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
860
861   blocking_task_runner_->PostTask(FROM_HERE,
862                                   base::Bind(&internal::RemoveStaleCacheFiles,
863                                              cache_,
864                                              resource_metadata_));
865   sync_client_->StartProcessingBacklog();
866 }
867
868 void FileSystem::GetMetadata(
869     const GetFilesystemMetadataCallback& callback) {
870   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
871   DCHECK(!callback.is_null());
872
873   FileSystemMetadata metadata;
874   metadata.refreshing = change_list_loader_->IsRefreshing();
875
876   // Metadata related to delta update.
877   metadata.last_update_check_time = last_update_check_time_;
878   metadata.last_update_check_error = last_update_check_error_;
879
880   base::PostTaskAndReplyWithResult(
881       blocking_task_runner_,
882       FROM_HERE,
883       base::Bind(&internal::ResourceMetadata::GetLargestChangestamp,
884                  base::Unretained(resource_metadata_)),
885       base::Bind(&OnGetLargestChangestamp, metadata, callback));
886 }
887
888 void FileSystem::MarkCacheFileAsMounted(
889     const base::FilePath& drive_file_path,
890     const MarkMountedCallback& callback) {
891   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
892   DCHECK(!callback.is_null());
893
894   base::FilePath* cache_file_path = new base::FilePath;
895   base::PostTaskAndReplyWithResult(
896       blocking_task_runner_,
897       FROM_HERE,
898       base::Bind(&MarkCacheFileAsMountedInternal,
899                  resource_metadata_,
900                  cache_,
901                  drive_file_path,
902                  cache_file_path),
903       base::Bind(&RunMarkMountedCallback,
904                  callback,
905                  base::Owned(cache_file_path)));
906 }
907
908 void FileSystem::MarkCacheFileAsUnmounted(
909     const base::FilePath& cache_file_path,
910     const FileOperationCallback& callback) {
911   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
912   DCHECK(!callback.is_null());
913
914   if (!cache_->IsUnderFileCacheDirectory(cache_file_path)) {
915     callback.Run(FILE_ERROR_FAILED);
916     return;
917   }
918
919   base::PostTaskAndReplyWithResult(
920       blocking_task_runner_,
921       FROM_HERE,
922       base::Bind(&internal::FileCache::MarkAsUnmounted,
923                  base::Unretained(cache_),
924                  cache_file_path),
925       callback);
926 }
927
928 void FileSystem::GetCacheEntry(
929     const base::FilePath& drive_file_path,
930     const GetCacheEntryCallback& callback) {
931   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
932   DCHECK(!callback.is_null());
933
934   FileCacheEntry* cache_entry = new FileCacheEntry;
935   base::PostTaskAndReplyWithResult(
936       blocking_task_runner_,
937       FROM_HERE,
938       base::Bind(&GetCacheEntryInternal,
939                  resource_metadata_,
940                  cache_,
941                  drive_file_path,
942                  cache_entry),
943       base::Bind(&RunGetCacheEntryCallback,
944                  callback,
945                  base::Owned(cache_entry)));
946 }
947
948 void FileSystem::AddPermission(const base::FilePath& drive_file_path,
949                                const std::string& email,
950                                google_apis::drive::PermissionRole role,
951                                const FileOperationCallback& callback) {
952   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
953   DCHECK(!callback.is_null());
954
955   // Resolve the resource id.
956   ResourceEntry* const entry = new ResourceEntry;
957   base::PostTaskAndReplyWithResult(
958       blocking_task_runner_.get(),
959       FROM_HERE,
960       base::Bind(&internal::ResourceMetadata::GetResourceEntryByPath,
961                  base::Unretained(resource_metadata_),
962                  drive_file_path,
963                  entry),
964       base::Bind(&FileSystem::AddPermissionAfterGetResourceEntry,
965                  weak_ptr_factory_.GetWeakPtr(),
966                  email,
967                  role,
968                  callback,
969                  base::Owned(entry)));
970 }
971
972 void FileSystem::AddPermissionAfterGetResourceEntry(
973     const std::string& email,
974     google_apis::drive::PermissionRole role,
975     const FileOperationCallback& callback,
976     ResourceEntry* entry,
977     FileError error) {
978   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
979
980   if (error != FILE_ERROR_OK) {
981     callback.Run(error);
982     return;
983   }
984
985   scheduler_->AddPermission(
986       entry->resource_id(),
987       email,
988       role,
989       base::Bind(&RunFileOperationCallbackAsEntryActionCallback, callback));
990 }
991
992 void FileSystem::OpenFile(const base::FilePath& file_path,
993                           OpenMode open_mode,
994                           const std::string& mime_type,
995                           const OpenFileCallback& callback) {
996   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
997   DCHECK(!callback.is_null());
998
999   open_file_operation_->OpenFile(file_path, open_mode, mime_type, callback);
1000 }
1001
1002 void FileSystem::GetPathFromResourceId(const std::string& resource_id,
1003                                        const GetFilePathCallback& callback) {
1004   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1005   DCHECK(!callback.is_null());
1006
1007   base::FilePath* const file_path = new base::FilePath();
1008   base::PostTaskAndReplyWithResult(
1009       blocking_task_runner_,
1010       FROM_HERE,
1011       base::Bind(&GetPathFromResourceIdOnBlockingPool,
1012                  resource_metadata_,
1013                  resource_id,
1014                  file_path),
1015       base::Bind(&GetPathFromResourceIdAfterGetPath,
1016                  base::Owned(file_path),
1017                  callback));
1018 }
1019 }  // namespace drive