1 // Copyright 2013 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/sync_file_system/drive_backend/remote_to_local_syncer.h"
8 #include "base/callback.h"
9 #include "base/format_macros.h"
10 #include "base/location.h"
11 #include "base/logging.h"
12 #include "base/message_loop/message_loop_proxy.h"
13 #include "base/task_runner_util.h"
14 #include "chrome/browser/drive/drive_api_util.h"
15 #include "chrome/browser/drive/drive_service_interface.h"
16 #include "chrome/browser/sync_file_system/drive_backend/callback_helper.h"
17 #include "chrome/browser/sync_file_system/drive_backend/drive_backend_util.h"
18 #include "chrome/browser/sync_file_system/drive_backend/metadata_database.h"
19 #include "chrome/browser/sync_file_system/drive_backend/sync_engine_context.h"
20 #include "chrome/browser/sync_file_system/logger.h"
21 #include "chrome/browser/sync_file_system/syncable_file_system_util.h"
22 #include "extensions/common/extension.h"
23 #include "google_apis/drive/drive_api_parser.h"
24 #include "google_apis/drive/gdata_wapi_parser.h"
25 #include "webkit/common/fileapi/file_system_util.h"
27 namespace sync_file_system {
28 namespace drive_backend {
32 bool BuildFileSystemURL(
33 MetadataDatabase* metadata_database,
34 const FileTracker& tracker,
35 fileapi::FileSystemURL* url) {
37 if (!metadata_database->BuildPathForTracker(
38 tracker.tracker_id(), &path))
42 extensions::Extension::GetBaseURLFromExtensionId(tracker.app_id());
43 *url = sync_file_system::CreateSyncableFileSystemURL(origin, path);
48 bool HasFolderAsParent(const FileDetails& details,
49 const std::string& folder_id) {
50 for (int i = 0; i < details.parent_folder_ids_size(); ++i) {
51 if (details.parent_folder_ids(i) == folder_id)
57 bool HasDisabledAppRoot(MetadataDatabase* database,
58 const FileTracker& tracker) {
59 DCHECK(tracker.active());
60 FileTracker app_root_tracker;
61 if (database->FindAppRootTracker(tracker.app_id(), &app_root_tracker)) {
62 DCHECK(app_root_tracker.tracker_kind() == TRACKER_KIND_APP_ROOT ||
63 app_root_tracker.tracker_kind() == TRACKER_KIND_DISABLED_APP_ROOT);
64 return app_root_tracker.tracker_kind() == TRACKER_KIND_DISABLED_APP_ROOT;
69 scoped_ptr<FileMetadata> GetFileMetadata(MetadataDatabase* database,
70 const std::string& file_id) {
71 scoped_ptr<FileMetadata> metadata(new FileMetadata);
72 if (!database->FindFileByFileID(file_id, metadata.get()))
74 return metadata.Pass();
79 RemoteToLocalSyncer::RemoteToLocalSyncer(SyncEngineContext* sync_context)
80 : sync_context_(sync_context),
81 sync_action_(SYNC_ACTION_NONE),
83 sync_root_deletion_(false),
84 weak_ptr_factory_(this) {
87 RemoteToLocalSyncer::~RemoteToLocalSyncer() {
90 void RemoteToLocalSyncer::RunExclusive(const SyncStatusCallback& callback) {
91 if (!drive_service() || !metadata_database() || !remote_change_processor()) {
92 util::Log(logging::LOG_VERBOSE, FROM_HERE,
93 "[Remote -> Local] Context not ready.");
95 callback.Run(SYNC_STATUS_FAILED);
99 SyncStatusCallback wrapped_callback = base::Bind(
100 &RemoteToLocalSyncer::SyncCompleted, weak_ptr_factory_.GetWeakPtr(),
101 base::Bind(&RemoteToLocalSyncer::FinalizeSync,
102 weak_ptr_factory_.GetWeakPtr(),
105 dirty_tracker_ = make_scoped_ptr(new FileTracker);
106 if (metadata_database()->GetNormalPriorityDirtyTracker(
107 dirty_tracker_.get())) {
108 util::Log(logging::LOG_VERBOSE, FROM_HERE,
109 "[Remote -> Local] Start: tracker_id=%" PRId64,
110 dirty_tracker_->tracker_id());
111 ResolveRemoteChange(wrapped_callback);
115 util::Log(logging::LOG_VERBOSE, FROM_HERE,
116 "[Remote -> Local] Nothing to do.");
117 sync_context_->GetWorkerTaskRunner()->PostTask(
119 base::Bind(callback, SYNC_STATUS_NO_CHANGE_TO_SYNC));
122 void RemoteToLocalSyncer::ResolveRemoteChange(
123 const SyncStatusCallback& callback) {
124 DCHECK(dirty_tracker_);
125 remote_metadata_ = GetFileMetadata(
126 metadata_database(), dirty_tracker_->file_id());
128 if (!remote_metadata_ || !remote_metadata_->has_details()) {
129 if (remote_metadata_ && !remote_metadata_->has_details()) {
130 LOG(ERROR) << "Missing details of a remote file: "
131 << remote_metadata_->file_id();
134 util::Log(logging::LOG_VERBOSE, FROM_HERE,
135 "[Remote -> Local]: Missing remote metadata case.");
136 HandleMissingRemoteMetadata(callback);
140 DCHECK(remote_metadata_);
141 DCHECK(remote_metadata_->has_details());
142 const FileDetails& remote_details = remote_metadata_->details();
144 if (!dirty_tracker_->active() ||
145 HasDisabledAppRoot(metadata_database(), *dirty_tracker_)) {
146 // Handle inactive tracker in SyncCompleted.
147 util::Log(logging::LOG_VERBOSE, FROM_HERE,
148 "[Remote -> Local]: Inactive tracker case.");
149 callback.Run(SYNC_STATUS_OK);
153 DCHECK(dirty_tracker_->active());
154 DCHECK(!HasDisabledAppRoot(metadata_database(), *dirty_tracker_));
156 if (!dirty_tracker_->has_synced_details()) {
157 LOG(ERROR) << "Missing synced_details of an active tracker: "
158 << dirty_tracker_->tracker_id();
160 callback.Run(SYNC_STATUS_FAILED);
164 DCHECK(dirty_tracker_->has_synced_details());
165 const FileDetails& synced_details = dirty_tracker_->synced_details();
167 if (dirty_tracker_->tracker_id() ==
168 metadata_database()->GetSyncRootTrackerID()) {
169 if (remote_details.missing() ||
170 synced_details.title() != remote_details.title() ||
171 remote_details.parent_folder_ids_size()) {
172 util::Log(logging::LOG_VERBOSE, FROM_HERE,
173 "[Remote -> Local]: Sync-root deletion.");
174 HandleSyncRootDeletion(callback);
177 util::Log(logging::LOG_VERBOSE, FROM_HERE,
178 "[Remote -> Local]: Trivial sync-root change.");
179 callback.Run(SYNC_STATUS_OK);
183 DCHECK_NE(dirty_tracker_->tracker_id(),
184 metadata_database()->GetSyncRootTrackerID());
186 if (remote_details.missing()) {
187 if (!synced_details.missing()) {
188 util::Log(logging::LOG_VERBOSE, FROM_HERE,
189 "[Remote -> Local]: Remote file deletion.");
190 HandleDeletion(callback);
194 DCHECK(synced_details.missing());
195 LOG(ERROR) << "Found a stray missing tracker: "
196 << dirty_tracker_->file_id();
198 callback.Run(SYNC_STATUS_OK);
202 // Most of remote_details field is valid from here.
203 DCHECK(!remote_details.missing());
205 if (synced_details.file_kind() != remote_details.file_kind()) {
206 LOG(ERROR) << "Found type mismatch between remote and local file: "
207 << dirty_tracker_->file_id()
208 << " type: (local) " << synced_details.file_kind()
209 << " vs (remote) " << remote_details.file_kind();
211 callback.Run(SYNC_STATUS_FAILED);
214 DCHECK_EQ(synced_details.file_kind(), remote_details.file_kind());
216 if (synced_details.file_kind() == FILE_KIND_UNSUPPORTED) {
217 LOG(ERROR) << "Found an unsupported active file: "
218 << remote_metadata_->file_id();
220 callback.Run(SYNC_STATUS_FAILED);
223 DCHECK(remote_details.file_kind() == FILE_KIND_FILE ||
224 remote_details.file_kind() == FILE_KIND_FOLDER);
226 if (synced_details.title() != remote_details.title()) {
227 // Handle rename as deletion + addition.
228 util::Log(logging::LOG_VERBOSE, FROM_HERE,
229 "[Remote -> Local]: Detected file rename.");
230 Prepare(base::Bind(&RemoteToLocalSyncer::DidPrepareForDeletion,
231 weak_ptr_factory_.GetWeakPtr(), callback));
234 DCHECK_EQ(synced_details.title(), remote_details.title());
236 FileTracker parent_tracker;
237 if (!metadata_database()->FindTrackerByTrackerID(
238 dirty_tracker_->parent_tracker_id(), &parent_tracker)) {
239 LOG(ERROR) << "Missing parent tracker for a non sync-root tracker: "
240 << dirty_tracker_->file_id();
242 callback.Run(SYNC_STATUS_FAILED);
246 if (!HasFolderAsParent(remote_details, parent_tracker.file_id())) {
247 // Handle reorganize as deletion + addition.
248 util::Log(logging::LOG_VERBOSE, FROM_HERE,
249 "[Remote -> Local]: Detected file reorganize.");
250 Prepare(base::Bind(&RemoteToLocalSyncer::DidPrepareForDeletion,
251 weak_ptr_factory_.GetWeakPtr(), callback));
255 if (synced_details.file_kind() == FILE_KIND_FILE) {
256 if (synced_details.md5() != remote_details.md5()) {
257 util::Log(logging::LOG_VERBOSE, FROM_HERE,
258 "[Remote -> Local]: Detected file content update.");
259 HandleContentUpdate(callback);
263 DCHECK_EQ(FILE_KIND_FOLDER, synced_details.file_kind());
264 if (synced_details.missing()) {
265 util::Log(logging::LOG_VERBOSE, FROM_HERE,
266 "[Remote -> Local]: Detected folder update.");
267 HandleFolderUpdate(callback);
270 if (dirty_tracker_->needs_folder_listing()) {
271 util::Log(logging::LOG_VERBOSE, FROM_HERE,
272 "[Remote -> Local]: Needs listing folder.");
273 ListFolderContent(callback);
276 callback.Run(SYNC_STATUS_OK);
280 util::Log(logging::LOG_VERBOSE, FROM_HERE,
281 "[Remote -> Local]: Trivial file change.");
282 callback.Run(SYNC_STATUS_OK);
285 void RemoteToLocalSyncer::HandleMissingRemoteMetadata(
286 const SyncStatusCallback& callback) {
287 DCHECK(dirty_tracker_);
289 drive_service()->GetFileResource(
290 dirty_tracker_->file_id(),
291 base::Bind(&RemoteToLocalSyncer::DidGetRemoteMetadata,
292 weak_ptr_factory_.GetWeakPtr(),
296 void RemoteToLocalSyncer::DidGetRemoteMetadata(
297 const SyncStatusCallback& callback,
298 google_apis::GDataErrorCode error,
299 scoped_ptr<google_apis::FileResource> entry) {
300 DCHECK(sync_context_->GetWorkerTaskRunner()->RunsTasksOnCurrentThread());
302 SyncStatusCode status = GDataErrorCodeToSyncStatusCode(error);
303 if (status != SYNC_STATUS_OK &&
304 error != google_apis::HTTP_NOT_FOUND) {
305 callback.Run(status);
309 if (error == google_apis::HTTP_NOT_FOUND) {
310 metadata_database()->UpdateByDeletedRemoteFile(
311 dirty_tracker_->file_id(), callback);
317 callback.Run(SYNC_STATUS_FAILED);
321 metadata_database()->UpdateByFileResource(
323 base::Bind(&RemoteToLocalSyncer::DidUpdateDatabaseForRemoteMetadata,
324 weak_ptr_factory_.GetWeakPtr(), callback));
327 void RemoteToLocalSyncer::DidUpdateDatabaseForRemoteMetadata(
328 const SyncStatusCallback& callback,
329 SyncStatusCode status) {
330 if (status != SYNC_STATUS_OK) {
331 callback.Run(status);
335 callback.Run(SYNC_STATUS_RETRY); // Do not update |dirty_tracker_|.
338 void RemoteToLocalSyncer::DidPrepareForAddOrUpdateFile(
339 const SyncStatusCallback& callback,
340 SyncStatusCode status) {
341 if (status != SYNC_STATUS_OK) {
342 callback.Run(status);
346 DCHECK(url_.is_valid());
347 DCHECK(local_metadata_);
348 DCHECK(local_changes_);
350 // Check if the local file exists.
351 if (local_metadata_->file_type == SYNC_FILE_TYPE_UNKNOWN ||
352 (!local_changes_->empty() && local_changes_->back().IsDelete())) {
353 sync_action_ = SYNC_ACTION_ADDED;
354 // Missing local file case.
355 // Download the file and add it to local as a new file.
356 DownloadFile(callback);
360 DCHECK(local_changes_->empty() || local_changes_->back().IsAddOrUpdate());
361 if (local_changes_->empty()) {
362 if (local_metadata_->file_type == SYNC_FILE_TYPE_FILE) {
363 sync_action_ = SYNC_ACTION_UPDATED;
364 // Download the file and overwrite the existing local file.
365 DownloadFile(callback);
369 DCHECK_EQ(SYNC_FILE_TYPE_DIRECTORY, local_metadata_->file_type);
371 // Got a remote regular file modification for existing local folder.
372 // Our policy prioritize folders in this case.
373 // Lower the priority of the tracker to prevent repeated remote sync to the
374 // same tracker, and let local-to-remote sync phase process this change.
375 metadata_database()->LowerTrackerPriority(dirty_tracker_->tracker_id());
376 remote_change_processor()->RecordFakeLocalChange(
378 FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE,
379 local_metadata_->file_type),
384 DCHECK(local_changes_->back().IsAddOrUpdate());
386 // Do nothing for the change now, and handle this in LocalToRemoteSync phase.
388 // Lower the priority of the tracker to prevent repeated remote sync to the
390 metadata_database()->LowerTrackerPriority(dirty_tracker_->tracker_id());
391 callback.Run(SYNC_STATUS_RETRY);
394 void RemoteToLocalSyncer::HandleFolderUpdate(
395 const SyncStatusCallback& callback) {
396 DCHECK(dirty_tracker_);
397 DCHECK(dirty_tracker_->active());
398 DCHECK(!HasDisabledAppRoot(metadata_database(), *dirty_tracker_));
400 DCHECK(remote_metadata_);
401 DCHECK(remote_metadata_->has_details());
402 DCHECK(!remote_metadata_->details().missing());
403 DCHECK_EQ(FILE_KIND_FOLDER, remote_metadata_->details().file_kind());
405 Prepare(base::Bind(&RemoteToLocalSyncer::DidPrepareForFolderUpdate,
406 weak_ptr_factory_.GetWeakPtr(), callback));
409 void RemoteToLocalSyncer::DidPrepareForFolderUpdate(
410 const SyncStatusCallback& callback,
411 SyncStatusCode status) {
412 if (status != SYNC_STATUS_OK) {
413 callback.Run(status);
417 DCHECK(url_.is_valid());
418 DCHECK(local_metadata_);
419 DCHECK(local_changes_);
421 // Check if the local file exists.
422 if (local_metadata_->file_type == SYNC_FILE_TYPE_UNKNOWN ||
423 (!local_changes_->empty() && local_changes_->back().IsDelete())) {
424 sync_action_ = SYNC_ACTION_ADDED;
425 // No local file exists at the path.
426 CreateFolder(callback);
430 if (local_metadata_->file_type == SYNC_FILE_TYPE_DIRECTORY) {
431 // There already exists a folder, nothing left to do.
432 if (dirty_tracker_->needs_folder_listing() &&
433 !dirty_tracker_->synced_details().missing()) {
434 ListFolderContent(callback);
436 callback.Run(SYNC_STATUS_OK);
441 DCHECK_EQ(SYNC_FILE_TYPE_FILE, local_metadata_->file_type);
442 sync_action_ = SYNC_ACTION_ADDED;
443 // Got a remote folder for existing local file.
444 // Our policy prioritize folders in this case.
445 CreateFolder(callback);
448 void RemoteToLocalSyncer::HandleSyncRootDeletion(
449 const SyncStatusCallback& callback) {
450 sync_root_deletion_ = true;
451 callback.Run(SYNC_STATUS_OK);
454 void RemoteToLocalSyncer::HandleDeletion(
455 const SyncStatusCallback& callback) {
456 DCHECK(dirty_tracker_);
457 DCHECK(dirty_tracker_->active());
458 DCHECK(!HasDisabledAppRoot(metadata_database(), *dirty_tracker_));
459 DCHECK(dirty_tracker_->has_synced_details());
460 DCHECK(!dirty_tracker_->synced_details().missing());
462 DCHECK(remote_metadata_);
463 DCHECK(remote_metadata_->has_details());
464 DCHECK(remote_metadata_->details().missing());
466 Prepare(base::Bind(&RemoteToLocalSyncer::DidPrepareForDeletion,
467 weak_ptr_factory_.GetWeakPtr(), callback));
470 void RemoteToLocalSyncer::DidPrepareForDeletion(
471 const SyncStatusCallback& callback,
472 SyncStatusCode status) {
473 if (status != SYNC_STATUS_OK) {
474 callback.Run(status);
478 DCHECK(url_.is_valid());
479 DCHECK(local_metadata_);
480 DCHECK(local_changes_);
482 // Check if the local file exists.
483 if (local_metadata_->file_type == SYNC_FILE_TYPE_UNKNOWN ||
484 (!local_changes_->empty() && local_changes_->back().IsDelete())) {
485 // No local file exists at the path.
486 callback.Run(SYNC_STATUS_OK);
490 DCHECK(local_changes_->empty() || local_changes_->back().IsAddOrUpdate());
491 if (local_changes_->empty()) {
492 sync_action_ = SYNC_ACTION_DELETED;
493 DeleteLocalFile(callback);
497 DCHECK(local_changes_->back().IsAddOrUpdate());
498 // File is remotely deleted and locally updated.
499 // Ignore the remote deletion and handle it as if applied successfully.
500 callback.Run(SYNC_STATUS_OK);
503 void RemoteToLocalSyncer::HandleContentUpdate(
504 const SyncStatusCallback& callback) {
505 DCHECK(dirty_tracker_);
506 DCHECK(dirty_tracker_->active());
507 DCHECK(!HasDisabledAppRoot(metadata_database(), *dirty_tracker_));
508 DCHECK(dirty_tracker_->has_synced_details());
509 DCHECK_EQ(FILE_KIND_FILE, dirty_tracker_->synced_details().file_kind());
511 DCHECK(remote_metadata_);
512 DCHECK(remote_metadata_->has_details());
513 DCHECK(!remote_metadata_->details().missing());
515 DCHECK_NE(dirty_tracker_->synced_details().md5(),
516 remote_metadata_->details().md5());
518 Prepare(base::Bind(&RemoteToLocalSyncer::DidPrepareForAddOrUpdateFile,
519 weak_ptr_factory_.GetWeakPtr(), callback));
522 void RemoteToLocalSyncer::ListFolderContent(
523 const SyncStatusCallback& callback) {
524 DCHECK(dirty_tracker_);
525 DCHECK(dirty_tracker_->active());
526 DCHECK(!HasDisabledAppRoot(metadata_database(), *dirty_tracker_));
527 DCHECK(dirty_tracker_->has_synced_details());
528 DCHECK(!dirty_tracker_->synced_details().missing());
529 DCHECK_EQ(FILE_KIND_FOLDER, dirty_tracker_->synced_details().file_kind());
530 DCHECK(dirty_tracker_->needs_folder_listing());
532 DCHECK(remote_metadata_);
533 DCHECK(remote_metadata_->has_details());
534 DCHECK(!remote_metadata_->details().missing());
536 // TODO(tzik): Replace this call with ChildList version.
537 drive_service()->GetFileListInDirectory(
538 dirty_tracker_->file_id(),
539 base::Bind(&RemoteToLocalSyncer::DidListFolderContent,
540 weak_ptr_factory_.GetWeakPtr(),
542 base::Passed(make_scoped_ptr(new FileIDList))));
545 void RemoteToLocalSyncer::DidListFolderContent(
546 const SyncStatusCallback& callback,
547 scoped_ptr<FileIDList> children,
548 google_apis::GDataErrorCode error,
549 scoped_ptr<google_apis::FileList> file_list) {
550 SyncStatusCode status = GDataErrorCodeToSyncStatusCode(error);
551 if (status != SYNC_STATUS_OK) {
552 callback.Run(status);
558 callback.Run(SYNC_STATUS_FAILED);
562 children->reserve(children->size() + file_list->items().size());
563 for (ScopedVector<google_apis::FileResource>::const_iterator itr =
564 file_list->items().begin();
565 itr != file_list->items().end();
567 children->push_back((*itr)->file_id());
570 if (!file_list->next_link().is_empty()) {
571 drive_service()->GetRemainingFileList(
572 file_list->next_link(),
573 base::Bind(&RemoteToLocalSyncer::DidListFolderContent,
574 weak_ptr_factory_.GetWeakPtr(),
575 callback, base::Passed(&children)));
579 metadata_database()->PopulateFolderByChildList(
580 dirty_tracker_->file_id(), *children, callback);
583 void RemoteToLocalSyncer::SyncCompleted(const SyncStatusCallback& callback,
584 SyncStatusCode status) {
585 util::Log(logging::LOG_VERBOSE, FROM_HERE,
586 "[Remote -> Local]: Finished: action=%s, tracker=%" PRId64
588 SyncActionToString(sync_action_), dirty_tracker_->tracker_id(),
589 SyncStatusCodeToString(status));
591 if (sync_root_deletion_) {
592 callback.Run(SYNC_STATUS_OK);
596 if (status == SYNC_STATUS_RETRY) {
597 callback.Run(SYNC_STATUS_OK);
601 if (status != SYNC_STATUS_OK) {
602 callback.Run(status);
606 DCHECK(dirty_tracker_);
607 DCHECK(remote_metadata_);
608 DCHECK(remote_metadata_->has_details());
610 FileDetails updated_details = remote_metadata_->details();
611 if (!dirty_tracker_->active() ||
612 HasDisabledAppRoot(metadata_database(), *dirty_tracker_)) {
613 // Operations for an inactive tracker don't update file content.
614 if (dirty_tracker_->has_synced_details())
615 updated_details.set_md5(dirty_tracker_->synced_details().md5());
616 if (!dirty_tracker_->active()) {
617 // Keep missing true, as the change hasn't been synced to local.
618 updated_details.clear_md5();
619 updated_details.set_missing(true);
622 metadata_database()->UpdateTracker(dirty_tracker_->tracker_id(),
627 void RemoteToLocalSyncer::FinalizeSync(const SyncStatusCallback& callback,
628 SyncStatusCode status) {
630 remote_change_processor()->FinalizeRemoteSync(
631 url_, false /* clear_local_change */, base::Bind(callback, status));
635 callback.Run(status);
638 void RemoteToLocalSyncer::Prepare(const SyncStatusCallback& callback) {
639 bool should_success = BuildFileSystemURL(
640 metadata_database(), *dirty_tracker_, &url_);
641 DCHECK(should_success);
642 DCHECK(url_.is_valid());
643 remote_change_processor()->PrepareForProcessRemoteChange(
645 base::Bind(&RemoteToLocalSyncer::DidPrepare,
646 weak_ptr_factory_.GetWeakPtr(),
650 void RemoteToLocalSyncer::DidPrepare(const SyncStatusCallback& callback,
651 SyncStatusCode status,
652 const SyncFileMetadata& local_metadata,
653 const FileChangeList& local_changes) {
654 if (status != SYNC_STATUS_OK) {
655 callback.Run(status);
660 local_metadata_.reset(new SyncFileMetadata(local_metadata));
661 local_changes_.reset(new FileChangeList(local_changes));
663 callback.Run(status);
666 void RemoteToLocalSyncer::DeleteLocalFile(const SyncStatusCallback& callback) {
667 remote_change_processor()->ApplyRemoteChange(
668 FileChange(FileChange::FILE_CHANGE_DELETE, SYNC_FILE_TYPE_UNKNOWN),
674 void RemoteToLocalSyncer::DownloadFile(const SyncStatusCallback& callback) {
675 DCHECK(sync_context_->GetWorkerTaskRunner()->RunsTasksOnCurrentThread());
677 base::Callback<void(webkit_blob::ScopedFile)> did_create_callback =
678 base::Bind(&RemoteToLocalSyncer::DidCreateTemporaryFileForDownload,
679 weak_ptr_factory_.GetWeakPtr(), callback);
681 sync_context_->GetFileTaskRunner()->PostTask(
683 CreateComposedFunction(
684 base::Bind(&CreateTemporaryFile,
685 make_scoped_refptr(sync_context_->GetFileTaskRunner())),
686 RelayCallbackToTaskRunner(
687 sync_context_->GetWorkerTaskRunner(), FROM_HERE,
688 did_create_callback)));
691 void RemoteToLocalSyncer::DidCreateTemporaryFileForDownload(
692 const SyncStatusCallback& callback,
693 webkit_blob::ScopedFile file) {
694 DCHECK(sync_context_->GetWorkerTaskRunner()->RunsTasksOnCurrentThread());
695 base::FilePath path = file.path();
696 drive_service()->DownloadFile(
697 path, remote_metadata_->file_id(),
698 base::Bind(&RemoteToLocalSyncer::DidDownloadFile,
699 weak_ptr_factory_.GetWeakPtr(),
700 callback, base::Passed(&file)),
701 google_apis::GetContentCallback(),
702 google_apis::ProgressCallback());
705 void RemoteToLocalSyncer::DidDownloadFile(const SyncStatusCallback& callback,
706 webkit_blob::ScopedFile file,
707 google_apis::GDataErrorCode error,
708 const base::FilePath&) {
709 DCHECK(sync_context_->GetWorkerTaskRunner()->RunsTasksOnCurrentThread());
711 SyncStatusCode status = GDataErrorCodeToSyncStatusCode(error);
712 if (status != SYNC_STATUS_OK) {
713 callback.Run(status);
717 base::FilePath path = file.path();
718 base::Callback<void(const std::string&)> did_calculate_callback =
719 base::Bind(&RemoteToLocalSyncer::DidCalculateMD5ForDownload,
720 weak_ptr_factory_.GetWeakPtr(),
721 callback, base::Passed(&file));
723 sync_context_->GetFileTaskRunner()->PostTask(
725 CreateComposedFunction(
726 base::Bind(&drive::util::GetMd5Digest, path),
727 RelayCallbackToTaskRunner(
728 sync_context_->GetWorkerTaskRunner(), FROM_HERE,
729 did_calculate_callback)));
732 void RemoteToLocalSyncer::DidCalculateMD5ForDownload(
733 const SyncStatusCallback& callback,
734 webkit_blob::ScopedFile file,
735 const std::string& md5) {
737 callback.Run(SYNC_FILE_ERROR_NOT_FOUND);
741 if (md5 != remote_metadata_->details().md5()) {
742 // File has been modified since last metadata retrieval.
744 // Lower the priority of the tracker to prevent repeated remote sync to the
746 metadata_database()->LowerTrackerPriority(dirty_tracker_->tracker_id());
747 callback.Run(SYNC_STATUS_RETRY);
751 base::FilePath path = file.path();
752 remote_change_processor()->ApplyRemoteChange(
753 FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE, SYNC_FILE_TYPE_FILE),
755 base::Bind(&RemoteToLocalSyncer::DidApplyDownload,
756 weak_ptr_factory_.GetWeakPtr(),
757 callback, base::Passed(&file)));
760 void RemoteToLocalSyncer::DidApplyDownload(const SyncStatusCallback& callback,
761 webkit_blob::ScopedFile,
762 SyncStatusCode status) {
763 if (status != SYNC_STATUS_OK)
764 metadata_database()->LowerTrackerPriority(dirty_tracker_->tracker_id());
765 callback.Run(status);
768 void RemoteToLocalSyncer::CreateFolder(const SyncStatusCallback& callback) {
769 remote_change_processor()->ApplyRemoteChange(
770 FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE,
771 SYNC_FILE_TYPE_DIRECTORY),
772 base::FilePath(), url_,
776 drive::DriveServiceInterface* RemoteToLocalSyncer::drive_service() {
777 return sync_context_->GetDriveService();
780 MetadataDatabase* RemoteToLocalSyncer::metadata_database() {
781 return sync_context_->GetMetadataDatabase();
784 RemoteChangeProcessor* RemoteToLocalSyncer::remote_change_processor() {
785 DCHECK(sync_context_->GetRemoteChangeProcessor());
786 return sync_context_->GetRemoteChangeProcessor();
789 } // namespace drive_backend
790 } // namespace sync_file_system