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.
5 #include "chrome/browser/chromeos/drive/file_system.h"
8 #include "base/file_util.h"
9 #include "base/platform_file.h"
10 #include "base/prefs/pref_service.h"
11 #include "chrome/browser/browser_process.h"
12 #include "chrome/browser/chromeos/drive/change_list_loader.h"
13 #include "chrome/browser/chromeos/drive/change_list_processor.h"
14 #include "chrome/browser/chromeos/drive/drive.pb.h"
15 #include "chrome/browser/chromeos/drive/file_cache.h"
16 #include "chrome/browser/chromeos/drive/file_system/copy_operation.h"
17 #include "chrome/browser/chromeos/drive/file_system/create_directory_operation.h"
18 #include "chrome/browser/chromeos/drive/file_system/create_file_operation.h"
19 #include "chrome/browser/chromeos/drive/file_system/download_operation.h"
20 #include "chrome/browser/chromeos/drive/file_system/get_file_for_saving_operation.h"
21 #include "chrome/browser/chromeos/drive/file_system/move_operation.h"
22 #include "chrome/browser/chromeos/drive/file_system/open_file_operation.h"
23 #include "chrome/browser/chromeos/drive/file_system/remove_operation.h"
24 #include "chrome/browser/chromeos/drive/file_system/search_operation.h"
25 #include "chrome/browser/chromeos/drive/file_system/touch_operation.h"
26 #include "chrome/browser/chromeos/drive/file_system/truncate_operation.h"
27 #include "chrome/browser/chromeos/drive/file_system/update_operation.h"
28 #include "chrome/browser/chromeos/drive/file_system_observer.h"
29 #include "chrome/browser/chromeos/drive/file_system_util.h"
30 #include "chrome/browser/chromeos/drive/job_scheduler.h"
31 #include "chrome/browser/chromeos/drive/logging.h"
32 #include "chrome/browser/chromeos/drive/remove_stale_cache_files.h"
33 #include "chrome/browser/chromeos/drive/resource_entry_conversion.h"
34 #include "chrome/browser/chromeos/drive/search_metadata.h"
35 #include "chrome/browser/chromeos/drive/sync_client.h"
36 #include "chrome/browser/drive/drive_service_interface.h"
37 #include "chrome/browser/google_apis/drive_api_parser.h"
38 #include "chrome/common/pref_names.h"
39 #include "content/public/browser/browser_thread.h"
41 using content::BrowserThread;
46 // Gets a ResourceEntry from the metadata, and overwrites its file info when the
47 // cached file is dirty.
48 FileError GetLocallyStoredResourceEntry(
49 internal::ResourceMetadata* resource_metadata,
50 internal::FileCache* cache,
51 const base::FilePath& file_path,
52 ResourceEntry* entry) {
54 FileError error = resource_metadata->GetIdByPath(file_path, &local_id);
55 if (error != FILE_ERROR_OK)
58 error = resource_metadata->GetResourceEntryById(local_id, entry);
59 if (error != FILE_ERROR_OK)
62 // For entries that will never be cached, use the original resource entry
64 if (!entry->has_file_specific_info() ||
65 entry->file_specific_info().is_hosted_document())
68 // When no dirty cache is found, use the original resource entry as is.
69 FileCacheEntry cache_entry;
70 if (!cache->GetCacheEntry(local_id, &cache_entry) || !cache_entry.is_dirty())
73 // If the cache is dirty, obtain the file info from the cache file itself.
74 base::FilePath local_cache_path;
75 error = cache->GetFile(local_id, &local_cache_path);
76 if (error != FILE_ERROR_OK)
79 base::PlatformFileInfo file_info;
80 if (!file_util::GetFileInfo(local_cache_path, &file_info))
81 return FILE_ERROR_NOT_FOUND;
83 SetPlatformFileInfoToResourceEntry(file_info, entry);
87 // Runs the callback with parameters.
88 void RunGetResourceEntryCallback(const GetResourceEntryCallback& callback,
89 scoped_ptr<ResourceEntry> entry,
91 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
92 DCHECK(!callback.is_null());
94 if (error != FILE_ERROR_OK)
96 callback.Run(error, entry.Pass());
99 // Used to implement Pin().
100 FileError PinInternal(internal::ResourceMetadata* resource_metadata,
101 internal::FileCache* cache,
102 const base::FilePath& file_path,
103 std::string* local_id) {
104 FileError error = resource_metadata->GetIdByPath(file_path, local_id);
105 if (error != FILE_ERROR_OK)
109 error = resource_metadata->GetResourceEntryById(*local_id, &entry);
110 if (error != FILE_ERROR_OK)
113 // TODO(hashimoto): Support pinning directories. crbug.com/127831
114 if (entry.file_info().is_directory())
115 return FILE_ERROR_NOT_A_FILE;
117 return cache->Pin(*local_id);
120 // Used to implement Unpin().
121 FileError UnpinInternal(internal::ResourceMetadata* resource_metadata,
122 internal::FileCache* cache,
123 const base::FilePath& file_path,
124 std::string* local_id) {
125 FileError error = resource_metadata->GetIdByPath(file_path, local_id);
126 if (error != FILE_ERROR_OK)
129 return cache->Unpin(*local_id);
132 // Used to implement MarkCacheFileAsMounted().
133 FileError MarkCacheFileAsMountedInternal(
134 internal::ResourceMetadata* resource_metadata,
135 internal::FileCache* cache,
136 const base::FilePath& drive_file_path,
137 base::FilePath* cache_file_path) {
138 std::string local_id;
139 FileError error = resource_metadata->GetIdByPath(drive_file_path, &local_id);
140 if (error != FILE_ERROR_OK)
143 return cache->MarkAsMounted(local_id, cache_file_path);
146 // Runs the callback with arguments.
147 void RunMarkMountedCallback(const MarkMountedCallback& callback,
148 base::FilePath* cache_file_path,
150 DCHECK(!callback.is_null());
151 callback.Run(error, *cache_file_path);
154 // Used to implement GetCacheEntryByPath.
155 bool GetCacheEntryByPathInternal(internal::ResourceMetadata* resource_metadata,
156 internal::FileCache* cache,
157 const base::FilePath& drive_file_path,
158 FileCacheEntry* cache_entry) {
160 if (resource_metadata->GetIdByPath(drive_file_path, &id) != FILE_ERROR_OK)
163 return cache->GetCacheEntry(id, cache_entry);
166 // Runs the callback with arguments.
167 void RunGetCacheEntryCallback(const GetCacheEntryCallback& callback,
168 const FileCacheEntry* cache_entry,
170 DCHECK(!callback.is_null());
171 callback.Run(success, *cache_entry);
174 // Callback for ResourceMetadata::GetLargestChangestamp.
175 // |callback| must not be null.
176 void OnGetLargestChangestamp(
177 FileSystemMetadata metadata, // Will be modified.
178 const GetFilesystemMetadataCallback& callback,
179 int64 largest_changestamp) {
180 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
181 DCHECK(!callback.is_null());
183 metadata.largest_changestamp = largest_changestamp;
184 callback.Run(metadata);
187 // Thin adapter to map GetFileCallback to FileOperationCallback.
188 void GetFileCallbackToFileOperationCallbackAdapter(
189 const FileOperationCallback& callback,
191 const base::FilePath& unused_file_path,
192 scoped_ptr<ResourceEntry> unused_entry) {
196 // Clears |resource_metadata| and |cache|.
197 FileError ResetOnBlockingPool(internal::ResourceMetadata* resource_metadata,
198 internal::FileCache* cache) {
199 FileError error = resource_metadata->Reset();
200 if (error != FILE_ERROR_OK)
202 return cache->ClearAll() ? FILE_ERROR_OK : FILE_ERROR_FAILED;
207 FileSystem::FileSystem(
208 PrefService* pref_service,
209 internal::FileCache* cache,
210 DriveServiceInterface* drive_service,
211 JobScheduler* scheduler,
212 internal::ResourceMetadata* resource_metadata,
213 base::SequencedTaskRunner* blocking_task_runner,
214 const base::FilePath& temporary_file_directory)
215 : pref_service_(pref_service),
217 drive_service_(drive_service),
218 scheduler_(scheduler),
219 resource_metadata_(resource_metadata),
220 last_update_check_error_(FILE_ERROR_OK),
221 blocking_task_runner_(blocking_task_runner),
222 temporary_file_directory_(temporary_file_directory),
223 weak_ptr_factory_(this) {
224 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
229 FileSystem::~FileSystem() {
230 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
232 change_list_loader_->RemoveObserver(this);
235 void FileSystem::Reload(const FileOperationCallback& callback) {
236 // Discard the current loader and operation objects and renew them. This is to
237 // avoid that changes initiated before the metadata reset is applied after the
238 // reset, which may cause an inconsistent state.
239 // TODO(kinaba): callbacks held in the subcomponents are discarded. We might
240 // want to have a way to abort and flush callbacks in in-flight operations.
243 base::PostTaskAndReplyWithResult(
244 blocking_task_runner_,
246 base::Bind(&ResetOnBlockingPool, resource_metadata_, cache_),
247 base::Bind(&FileSystem::ReloadAfterReset,
248 weak_ptr_factory_.GetWeakPtr(),
252 void FileSystem::ReloadAfterReset(const FileOperationCallback& callback,
254 if (error != FILE_ERROR_OK) {
255 LOG(ERROR) << "Failed to reload Drive file system: "
256 << FileErrorToString(error);
261 change_list_loader_->LoadIfNeeded(
262 internal::DirectoryFetchInfo(),
263 base::Bind(&FileSystem::OnUpdateChecked, weak_ptr_factory_.GetWeakPtr()));
267 void FileSystem::ResetComponents() {
268 file_system::OperationObserver* observer = this;
269 copy_operation_.reset(
270 new file_system::CopyOperation(blocking_task_runner_.get(),
276 temporary_file_directory_));
277 create_directory_operation_.reset(new file_system::CreateDirectoryOperation(
278 blocking_task_runner_.get(), observer, scheduler_, resource_metadata_));
279 create_file_operation_.reset(
280 new file_system::CreateFileOperation(blocking_task_runner_.get(),
285 move_operation_.reset(
286 new file_system::MoveOperation(blocking_task_runner_.get(),
289 resource_metadata_));
290 open_file_operation_.reset(
291 new file_system::OpenFileOperation(blocking_task_runner_.get(),
296 temporary_file_directory_));
297 remove_operation_.reset(
298 new file_system::RemoveOperation(blocking_task_runner_.get(),
303 touch_operation_.reset(new file_system::TouchOperation(
304 blocking_task_runner_.get(), observer, scheduler_, resource_metadata_));
305 truncate_operation_.reset(
306 new file_system::TruncateOperation(blocking_task_runner_.get(),
311 temporary_file_directory_));
312 download_operation_.reset(
313 new file_system::DownloadOperation(blocking_task_runner_.get(),
318 temporary_file_directory_));
319 update_operation_.reset(
320 new file_system::UpdateOperation(blocking_task_runner_.get(),
325 search_operation_.reset(new file_system::SearchOperation(
326 blocking_task_runner_.get(), scheduler_, resource_metadata_));
327 get_file_for_saving_operation_.reset(
328 new file_system::GetFileForSavingOperation(blocking_task_runner_.get(),
333 temporary_file_directory_));
335 sync_client_.reset(new internal::SyncClient(blocking_task_runner_.get(),
340 temporary_file_directory_));
342 change_list_loader_.reset(new internal::ChangeListLoader(
343 blocking_task_runner_.get(),
347 change_list_loader_->AddObserver(this);
350 void FileSystem::CheckForUpdates() {
351 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
352 DVLOG(1) << "CheckForUpdates";
354 change_list_loader_->CheckForUpdates(
355 base::Bind(&FileSystem::OnUpdateChecked, weak_ptr_factory_.GetWeakPtr()));
358 void FileSystem::OnUpdateChecked(FileError error) {
359 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
360 DVLOG(1) << "CheckForUpdates finished: " << FileErrorToString(error);
361 last_update_check_time_ = base::Time::Now();
362 last_update_check_error_ = error;
365 void FileSystem::AddObserver(FileSystemObserver* observer) {
366 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
367 observers_.AddObserver(observer);
370 void FileSystem::RemoveObserver(FileSystemObserver* observer) {
371 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
372 observers_.RemoveObserver(observer);
375 void FileSystem::TransferFileFromLocalToRemote(
376 const base::FilePath& local_src_file_path,
377 const base::FilePath& remote_dest_file_path,
378 const FileOperationCallback& callback) {
379 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
380 DCHECK(!callback.is_null());
381 copy_operation_->TransferFileFromLocalToRemote(local_src_file_path,
382 remote_dest_file_path,
386 void FileSystem::Copy(const base::FilePath& src_file_path,
387 const base::FilePath& dest_file_path,
388 bool preserve_last_modified,
389 const FileOperationCallback& callback) {
390 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
391 DCHECK(!callback.is_null());
392 copy_operation_->Copy(
393 src_file_path, dest_file_path, preserve_last_modified, callback);
396 void FileSystem::Move(const base::FilePath& src_file_path,
397 const base::FilePath& dest_file_path,
398 bool preserve_last_modified,
399 const FileOperationCallback& callback) {
400 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
401 DCHECK(!callback.is_null());
402 move_operation_->Move(
403 src_file_path, dest_file_path, preserve_last_modified, callback);
406 void FileSystem::Remove(const base::FilePath& file_path,
408 const FileOperationCallback& callback) {
409 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
410 DCHECK(!callback.is_null());
411 remove_operation_->Remove(file_path, is_recursive, callback);
414 void FileSystem::CreateDirectory(
415 const base::FilePath& directory_path,
418 const FileOperationCallback& callback) {
419 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
420 DCHECK(!callback.is_null());
422 // Ensure its parent directory is loaded to the local metadata.
423 LoadDirectoryIfNeeded(
424 directory_path.DirName(),
425 base::Bind(&FileSystem::CreateDirectoryAfterLoad,
426 weak_ptr_factory_.GetWeakPtr(),
427 directory_path, is_exclusive, is_recursive, callback));
430 void FileSystem::CreateDirectoryAfterLoad(
431 const base::FilePath& directory_path,
434 const FileOperationCallback& callback,
435 FileError load_error) {
436 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
437 DCHECK(!callback.is_null());
439 if (load_error != FILE_ERROR_OK) {
440 callback.Run(load_error);
444 create_directory_operation_->CreateDirectory(
445 directory_path, is_exclusive, is_recursive, callback);
448 void FileSystem::CreateFile(const base::FilePath& file_path,
450 const std::string& mime_type,
451 const FileOperationCallback& callback) {
452 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
453 DCHECK(!callback.is_null());
454 create_file_operation_->CreateFile(
455 file_path, is_exclusive, mime_type, callback);
458 void FileSystem::TouchFile(const base::FilePath& file_path,
459 const base::Time& last_access_time,
460 const base::Time& last_modified_time,
461 const FileOperationCallback& callback) {
462 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
463 DCHECK(!last_access_time.is_null());
464 DCHECK(!last_modified_time.is_null());
465 DCHECK(!callback.is_null());
466 touch_operation_->TouchFile(
467 file_path, last_access_time, last_modified_time, callback);
470 void FileSystem::TruncateFile(const base::FilePath& file_path,
472 const FileOperationCallback& callback) {
473 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
474 DCHECK(!callback.is_null());
475 truncate_operation_->Truncate(file_path, length, callback);
478 void FileSystem::Pin(const base::FilePath& file_path,
479 const FileOperationCallback& callback) {
480 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
481 DCHECK(!callback.is_null());
483 std::string* local_id = new std::string;
484 base::PostTaskAndReplyWithResult(
485 blocking_task_runner_,
487 base::Bind(&PinInternal, resource_metadata_, cache_, file_path, local_id),
488 base::Bind(&FileSystem::FinishPin,
489 weak_ptr_factory_.GetWeakPtr(),
491 base::Owned(local_id)));
494 void FileSystem::FinishPin(const FileOperationCallback& callback,
495 const std::string* local_id,
497 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
498 DCHECK(!callback.is_null());
500 if (error == FILE_ERROR_OK)
501 sync_client_->AddFetchTask(*local_id);
505 void FileSystem::Unpin(const base::FilePath& file_path,
506 const FileOperationCallback& callback) {
507 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
508 DCHECK(!callback.is_null());
510 std::string* local_id = new std::string;
511 base::PostTaskAndReplyWithResult(
512 blocking_task_runner_,
514 base::Bind(&UnpinInternal,
519 base::Bind(&FileSystem::FinishUnpin,
520 weak_ptr_factory_.GetWeakPtr(),
522 base::Owned(local_id)));
525 void FileSystem::FinishUnpin(const FileOperationCallback& callback,
526 const std::string* local_id,
528 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
529 DCHECK(!callback.is_null());
531 if (error == FILE_ERROR_OK)
532 sync_client_->RemoveFetchTask(*local_id);
536 void FileSystem::GetFileByPath(const base::FilePath& file_path,
537 const GetFileCallback& callback) {
538 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
539 DCHECK(!callback.is_null());
541 download_operation_->EnsureFileDownloadedByPath(
543 ClientContext(USER_INITIATED),
544 GetFileContentInitializedCallback(),
545 google_apis::GetContentCallback(),
549 void FileSystem::GetFileByPathForSaving(const base::FilePath& file_path,
550 const GetFileCallback& callback) {
551 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
552 DCHECK(!callback.is_null());
554 get_file_for_saving_operation_->GetFileForSaving(file_path, callback);
557 void FileSystem::GetFileContentByPath(
558 const base::FilePath& file_path,
559 const GetFileContentInitializedCallback& initialized_callback,
560 const google_apis::GetContentCallback& get_content_callback,
561 const FileOperationCallback& completion_callback) {
562 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
563 DCHECK(!initialized_callback.is_null());
564 DCHECK(!get_content_callback.is_null());
565 DCHECK(!completion_callback.is_null());
567 download_operation_->EnsureFileDownloadedByPath(
569 ClientContext(USER_INITIATED),
570 initialized_callback,
571 get_content_callback,
572 base::Bind(&GetFileCallbackToFileOperationCallbackAdapter,
573 completion_callback));
576 void FileSystem::GetResourceEntryByPath(
577 const base::FilePath& file_path,
578 const GetResourceEntryCallback& callback) {
579 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
580 DCHECK(!callback.is_null());
582 scoped_ptr<ResourceEntry> entry(new ResourceEntry);
583 ResourceEntry* entry_ptr = entry.get();
584 base::PostTaskAndReplyWithResult(
585 blocking_task_runner_,
587 base::Bind(&GetLocallyStoredResourceEntry,
592 base::Bind(&FileSystem::GetResourceEntryByPathAfterGetEntry,
593 weak_ptr_factory_.GetWeakPtr(),
596 base::Passed(&entry)));
599 void FileSystem::GetResourceEntryByPathAfterGetEntry(
600 const base::FilePath& file_path,
601 const GetResourceEntryCallback& callback,
602 scoped_ptr<ResourceEntry> entry,
604 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
605 DCHECK(!callback.is_null());
607 if (error == FILE_ERROR_NOT_FOUND) {
608 // If the information about the path is not in the local ResourceMetadata,
609 // try fetching information of the directory and retry.
611 // Note: this forms mutual recursion between GetResourceEntryByPath and
612 // LoadDirectoryIfNeeded, because directory loading requires the existence
613 // of directory entry itself. The recursion terminates because we always go
614 // up the hierarchy by .DirName() bounded under the Drive root path.
615 if (util::GetDriveGrandRootPath().IsParent(file_path)) {
616 LoadDirectoryIfNeeded(
618 base::Bind(&FileSystem::GetResourceEntryByPathAfterLoad,
619 weak_ptr_factory_.GetWeakPtr(),
626 callback.Run(error, entry.Pass());
629 void FileSystem::GetResourceEntryByPathAfterLoad(
630 const base::FilePath& file_path,
631 const GetResourceEntryCallback& callback,
633 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
634 DCHECK(!callback.is_null());
636 if (error != FILE_ERROR_OK) {
637 callback.Run(error, scoped_ptr<ResourceEntry>());
641 scoped_ptr<ResourceEntry> entry(new ResourceEntry);
642 ResourceEntry* entry_ptr = entry.get();
643 base::PostTaskAndReplyWithResult(
644 blocking_task_runner_,
646 base::Bind(&GetLocallyStoredResourceEntry,
651 base::Bind(&RunGetResourceEntryCallback,
653 base::Passed(&entry)));
656 void FileSystem::ReadDirectoryByPath(
657 const base::FilePath& directory_path,
658 const ReadDirectoryCallback& callback) {
659 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
660 DCHECK(!callback.is_null());
662 LoadDirectoryIfNeeded(
664 base::Bind(&FileSystem::ReadDirectoryByPathAfterLoad,
665 weak_ptr_factory_.GetWeakPtr(),
670 void FileSystem::LoadDirectoryIfNeeded(const base::FilePath& directory_path,
671 const FileOperationCallback& callback) {
672 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
673 DCHECK(!callback.is_null());
675 GetResourceEntryByPath(
677 base::Bind(&FileSystem::LoadDirectoryIfNeededAfterGetEntry,
678 weak_ptr_factory_.GetWeakPtr(),
683 void FileSystem::LoadDirectoryIfNeededAfterGetEntry(
684 const base::FilePath& directory_path,
685 const FileOperationCallback& callback,
687 scoped_ptr<ResourceEntry> entry) {
688 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
689 DCHECK(!callback.is_null());
691 if (error != FILE_ERROR_OK) {
696 if (!entry->file_info().is_directory()) {
697 callback.Run(FILE_ERROR_NOT_A_DIRECTORY);
701 // Pass the directory fetch info so we can fetch the contents of the
702 // directory before loading change lists.
703 internal::DirectoryFetchInfo directory_fetch_info(
704 entry->resource_id(),
705 entry->directory_specific_info().changestamp());
706 change_list_loader_->LoadIfNeeded(directory_fetch_info, callback);
709 void FileSystem::ReadDirectoryByPathAfterLoad(
710 const base::FilePath& directory_path,
711 const ReadDirectoryCallback& callback,
713 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
714 DCHECK(!callback.is_null());
716 DLOG_IF(INFO, error != FILE_ERROR_OK) << "LoadIfNeeded failed. "
717 << FileErrorToString(error);
719 resource_metadata_->ReadDirectoryByPathOnUIThread(
721 base::Bind(&FileSystem::ReadDirectoryByPathAfterRead,
722 weak_ptr_factory_.GetWeakPtr(),
727 void FileSystem::ReadDirectoryByPathAfterRead(
728 const base::FilePath& directory_path,
729 const ReadDirectoryCallback& callback,
731 scoped_ptr<ResourceEntryVector> entries) {
732 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
733 DCHECK(!callback.is_null());
735 if (error != FILE_ERROR_OK) {
737 scoped_ptr<ResourceEntryVector>());
740 DCHECK(entries.get()); // This is valid for empty directories too.
742 // TODO(satorux): Stop handling hide_hosted_docs here. crbug.com/256520.
743 const bool hide_hosted_docs =
744 pref_service_->GetBoolean(prefs::kDisableDriveHostedFiles);
745 scoped_ptr<ResourceEntryVector> filtered(new ResourceEntryVector);
746 for (size_t i = 0; i < entries->size(); ++i) {
747 if (hide_hosted_docs &&
748 entries->at(i).file_specific_info().is_hosted_document()) {
751 filtered->push_back(entries->at(i));
754 callback.Run(FILE_ERROR_OK, filtered.Pass());
757 void FileSystem::GetAvailableSpace(
758 const GetAvailableSpaceCallback& callback) {
759 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
760 DCHECK(!callback.is_null());
762 scheduler_->GetAboutResource(
763 base::Bind(&FileSystem::OnGetAboutResource,
764 weak_ptr_factory_.GetWeakPtr(),
768 void FileSystem::OnGetAboutResource(
769 const GetAvailableSpaceCallback& callback,
770 google_apis::GDataErrorCode status,
771 scoped_ptr<google_apis::AboutResource> about_resource) {
772 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
773 DCHECK(!callback.is_null());
775 FileError error = GDataToFileError(status);
776 if (error != FILE_ERROR_OK) {
777 callback.Run(error, -1, -1);
780 DCHECK(about_resource);
782 callback.Run(FILE_ERROR_OK,
783 about_resource->quota_bytes_total(),
784 about_resource->quota_bytes_used());
787 void FileSystem::GetShareUrl(
788 const base::FilePath& file_path,
789 const GURL& embed_origin,
790 const GetShareUrlCallback& callback) {
791 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
792 DCHECK(!callback.is_null());
794 // Resolve the resource id.
795 resource_metadata_->GetResourceEntryByPathOnUIThread(
797 base::Bind(&FileSystem::GetShareUrlAfterGetResourceEntry,
798 weak_ptr_factory_.GetWeakPtr(),
804 void FileSystem::GetShareUrlAfterGetResourceEntry(
805 const base::FilePath& file_path,
806 const GURL& embed_origin,
807 const GetShareUrlCallback& callback,
809 scoped_ptr<ResourceEntry> entry) {
810 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
811 DCHECK(!callback.is_null());
813 if (error != FILE_ERROR_OK) {
814 callback.Run(error, GURL());
817 if (util::IsSpecialResourceId(entry->resource_id())) {
818 // Do not load special directories. Just return.
819 callback.Run(FILE_ERROR_FAILED, GURL());
823 scheduler_->GetShareUrl(
824 entry->resource_id(),
826 ClientContext(USER_INITIATED),
827 base::Bind(&FileSystem::OnGetResourceEntryForGetShareUrl,
828 weak_ptr_factory_.GetWeakPtr(),
832 void FileSystem::OnGetResourceEntryForGetShareUrl(
833 const GetShareUrlCallback& callback,
834 google_apis::GDataErrorCode status,
835 const GURL& share_url) {
836 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
837 DCHECK(!callback.is_null());
839 FileError error = GDataToFileError(status);
840 if (error != FILE_ERROR_OK) {
841 callback.Run(error, GURL());
845 if (share_url.is_empty()) {
846 callback.Run(FILE_ERROR_FAILED, GURL());
850 callback.Run(FILE_ERROR_OK, share_url);
853 void FileSystem::Search(const std::string& search_query,
854 const GURL& next_link,
855 const SearchCallback& callback) {
856 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
857 DCHECK(!callback.is_null());
858 search_operation_->Search(search_query, next_link, callback);
861 void FileSystem::SearchMetadata(const std::string& query,
863 int at_most_num_matches,
864 const SearchMetadataCallback& callback) {
865 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
867 // TODO(satorux): Stop handling hide_hosted_docs here. crbug.com/256520.
868 if (pref_service_->GetBoolean(prefs::kDisableDriveHostedFiles))
869 options |= SEARCH_METADATA_EXCLUDE_HOSTED_DOCUMENTS;
871 drive::internal::SearchMetadata(blocking_task_runner_,
879 void FileSystem::OnDirectoryChangedByOperation(
880 const base::FilePath& directory_path) {
881 OnDirectoryChanged(directory_path);
884 void FileSystem::OnCacheFileUploadNeededByOperation(
885 const std::string& local_id) {
886 sync_client_->AddUploadTask(local_id);
889 void FileSystem::OnDirectoryChanged(const base::FilePath& directory_path) {
890 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
892 FOR_EACH_OBSERVER(FileSystemObserver, observers_,
893 OnDirectoryChanged(directory_path));
896 void FileSystem::OnLoadFromServerComplete() {
897 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
899 sync_client_->StartCheckingExistingPinnedFiles();
902 void FileSystem::OnInitialLoadComplete() {
903 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
905 blocking_task_runner_->PostTask(FROM_HERE,
906 base::Bind(&internal::RemoveStaleCacheFiles,
908 resource_metadata_));
909 sync_client_->StartProcessingBacklog();
912 void FileSystem::GetMetadata(
913 const GetFilesystemMetadataCallback& callback) {
914 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
915 DCHECK(!callback.is_null());
917 FileSystemMetadata metadata;
918 metadata.refreshing = change_list_loader_->IsRefreshing();
920 // Metadata related to delta update.
921 metadata.last_update_check_time = last_update_check_time_;
922 metadata.last_update_check_error = last_update_check_error_;
924 base::PostTaskAndReplyWithResult(
925 blocking_task_runner_,
927 base::Bind(&internal::ResourceMetadata::GetLargestChangestamp,
928 base::Unretained(resource_metadata_)),
929 base::Bind(&OnGetLargestChangestamp, metadata, callback));
932 void FileSystem::MarkCacheFileAsMounted(
933 const base::FilePath& drive_file_path,
934 const MarkMountedCallback& callback) {
935 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
936 DCHECK(!callback.is_null());
938 base::FilePath* cache_file_path = new base::FilePath;
939 base::PostTaskAndReplyWithResult(
940 blocking_task_runner_,
942 base::Bind(&MarkCacheFileAsMountedInternal,
947 base::Bind(&RunMarkMountedCallback,
949 base::Owned(cache_file_path)));
952 void FileSystem::MarkCacheFileAsUnmounted(
953 const base::FilePath& cache_file_path,
954 const FileOperationCallback& callback) {
955 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
956 DCHECK(!callback.is_null());
958 if (!cache_->IsUnderFileCacheDirectory(cache_file_path)) {
959 callback.Run(FILE_ERROR_FAILED);
962 cache_->MarkAsUnmountedOnUIThread(cache_file_path, callback);
965 void FileSystem::GetCacheEntryByPath(
966 const base::FilePath& drive_file_path,
967 const GetCacheEntryCallback& callback) {
968 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
969 DCHECK(!callback.is_null());
971 FileCacheEntry* cache_entry = new FileCacheEntry;
972 base::PostTaskAndReplyWithResult(
973 blocking_task_runner_,
975 base::Bind(&GetCacheEntryByPathInternal,
980 base::Bind(&RunGetCacheEntryCallback,
982 base::Owned(cache_entry)));
985 void FileSystem::OpenFile(const base::FilePath& file_path,
987 const std::string& mime_type,
988 const OpenFileCallback& callback) {
989 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
990 DCHECK(!callback.is_null());
992 open_file_operation_->OpenFile(file_path, open_mode, mime_type, callback);