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/drive_backend_util.h"
17 #include "chrome/browser/sync_file_system/drive_backend/metadata_database.h"
18 #include "chrome/browser/sync_file_system/drive_backend/sync_engine_context.h"
19 #include "chrome/browser/sync_file_system/logger.h"
20 #include "chrome/browser/sync_file_system/syncable_file_system_util.h"
21 #include "extensions/common/extension.h"
22 #include "google_apis/drive/drive_api_parser.h"
23 #include "google_apis/drive/gdata_wapi_parser.h"
24 #include "webkit/common/fileapi/file_system_util.h"
26 namespace sync_file_system
{
27 namespace drive_backend
{
31 bool BuildFileSystemURL(
32 MetadataDatabase
* metadata_database
,
33 const FileTracker
& tracker
,
34 fileapi::FileSystemURL
* url
) {
36 if (!metadata_database
->BuildPathForTracker(
37 tracker
.tracker_id(), &path
))
41 extensions::Extension::GetBaseURLFromExtensionId(tracker
.app_id());
42 *url
= sync_file_system::CreateSyncableFileSystemURL(origin
, path
);
47 bool HasFolderAsParent(const FileDetails
& details
,
48 const std::string
& folder_id
) {
49 for (int i
= 0; i
< details
.parent_folder_ids_size(); ++i
) {
50 if (details
.parent_folder_ids(i
) == folder_id
)
56 bool HasDisabledAppRoot(MetadataDatabase
* database
,
57 const FileTracker
& tracker
) {
58 DCHECK(tracker
.active());
59 FileTracker app_root_tracker
;
60 if (database
->FindAppRootTracker(tracker
.app_id(), &app_root_tracker
)) {
61 DCHECK(app_root_tracker
.tracker_kind() == TRACKER_KIND_APP_ROOT
||
62 app_root_tracker
.tracker_kind() == TRACKER_KIND_DISABLED_APP_ROOT
);
63 return app_root_tracker
.tracker_kind() == TRACKER_KIND_DISABLED_APP_ROOT
;
68 scoped_ptr
<FileMetadata
> GetFileMetadata(MetadataDatabase
* database
,
69 const std::string
& file_id
) {
70 scoped_ptr
<FileMetadata
> metadata(new FileMetadata
);
71 if (!database
->FindFileByFileID(file_id
, metadata
.get()))
73 return metadata
.Pass();
78 RemoteToLocalSyncer::RemoteToLocalSyncer(SyncEngineContext
* sync_context
)
79 : sync_context_(sync_context
),
80 sync_action_(SYNC_ACTION_NONE
),
82 sync_root_deletion_(false),
83 weak_ptr_factory_(this) {
86 RemoteToLocalSyncer::~RemoteToLocalSyncer() {
89 void RemoteToLocalSyncer::Run(const SyncStatusCallback
& callback
) {
90 if (!drive_service() || !metadata_database() || !remote_change_processor()) {
91 util::Log(logging::LOG_VERBOSE
, FROM_HERE
,
92 "[Remote -> Local] Context not ready.");
94 callback
.Run(SYNC_STATUS_FAILED
);
98 SyncStatusCallback wrapped_callback
= base::Bind(
99 &RemoteToLocalSyncer::SyncCompleted
, weak_ptr_factory_
.GetWeakPtr(),
100 base::Bind(&RemoteToLocalSyncer::FinalizeSync
,
101 weak_ptr_factory_
.GetWeakPtr(),
104 dirty_tracker_
= make_scoped_ptr(new FileTracker
);
105 if (metadata_database()->GetNormalPriorityDirtyTracker(
106 dirty_tracker_
.get())) {
107 util::Log(logging::LOG_VERBOSE
, FROM_HERE
,
108 "[Remote -> Local] Start: tracker_id=%" PRId64
,
109 dirty_tracker_
->tracker_id());
110 ResolveRemoteChange(wrapped_callback
);
114 util::Log(logging::LOG_VERBOSE
, FROM_HERE
,
115 "[Remote -> Local] Nothing to do.");
116 base::MessageLoopProxy::current()->PostTask(
118 base::Bind(callback
, SYNC_STATUS_NO_CHANGE_TO_SYNC
));
121 void RemoteToLocalSyncer::ResolveRemoteChange(
122 const SyncStatusCallback
& callback
) {
123 DCHECK(dirty_tracker_
);
124 remote_metadata_
= GetFileMetadata(
125 metadata_database(), dirty_tracker_
->file_id());
127 if (!remote_metadata_
|| !remote_metadata_
->has_details()) {
128 if (remote_metadata_
&& !remote_metadata_
->has_details()) {
129 LOG(ERROR
) << "Missing details of a remote file: "
130 << remote_metadata_
->file_id();
133 util::Log(logging::LOG_VERBOSE
, FROM_HERE
,
134 "[Remote -> Local]: Missing remote file case.");
135 HandleMissingRemoteMetadata(callback
);
139 DCHECK(remote_metadata_
);
140 DCHECK(remote_metadata_
->has_details());
141 const FileDetails
& remote_details
= remote_metadata_
->details();
143 if (!dirty_tracker_
->active() ||
144 HasDisabledAppRoot(metadata_database(), *dirty_tracker_
)) {
145 // Handle inactive tracker in SyncCompleted.
146 util::Log(logging::LOG_VERBOSE
, FROM_HERE
,
147 "[Remote -> Local]: Inactive tracker case.");
148 callback
.Run(SYNC_STATUS_OK
);
152 DCHECK(dirty_tracker_
->active());
153 DCHECK(!HasDisabledAppRoot(metadata_database(), *dirty_tracker_
));
155 if (!dirty_tracker_
->has_synced_details()) {
156 LOG(ERROR
) << "Missing synced_details of an active tracker: "
157 << dirty_tracker_
->tracker_id();
159 callback
.Run(SYNC_STATUS_FAILED
);
163 DCHECK(dirty_tracker_
->has_synced_details());
164 const FileDetails
& synced_details
= dirty_tracker_
->synced_details();
166 if (dirty_tracker_
->tracker_id() ==
167 metadata_database()->GetSyncRootTrackerID()) {
168 if (remote_details
.missing() ||
169 synced_details
.title() != remote_details
.title() ||
170 remote_details
.parent_folder_ids_size()) {
171 util::Log(logging::LOG_VERBOSE
, FROM_HERE
,
172 "[Remote -> Local]: Sync-root deletion.");
173 HandleSyncRootDeletion(callback
);
176 util::Log(logging::LOG_VERBOSE
, FROM_HERE
,
177 "[Remote -> Local]: Trivial sync-root change.");
178 callback
.Run(SYNC_STATUS_OK
);
182 DCHECK_NE(dirty_tracker_
->tracker_id(),
183 metadata_database()->GetSyncRootTrackerID());
185 if (remote_details
.missing()) {
186 if (!synced_details
.missing()) {
187 util::Log(logging::LOG_VERBOSE
, FROM_HERE
,
188 "[Remote -> Local]: Remote file deletion.");
189 HandleDeletion(callback
);
193 DCHECK(synced_details
.missing());
194 LOG(ERROR
) << "Found a stray missing tracker: "
195 << dirty_tracker_
->file_id();
197 callback
.Run(SYNC_STATUS_OK
);
201 // Most of remote_details field is valid from here.
202 DCHECK(!remote_details
.missing());
204 if (synced_details
.file_kind() != remote_details
.file_kind()) {
205 LOG(ERROR
) << "Found type mismatch between remote and local file: "
206 << dirty_tracker_
->file_id()
207 << " type: (local) " << synced_details
.file_kind()
208 << " vs (remote) " << remote_details
.file_kind();
210 callback
.Run(SYNC_STATUS_FAILED
);
213 DCHECK_EQ(synced_details
.file_kind(), remote_details
.file_kind());
215 if (synced_details
.file_kind() == FILE_KIND_UNSUPPORTED
) {
216 LOG(ERROR
) << "Found an unsupported active file: "
217 << remote_metadata_
->file_id();
219 callback
.Run(SYNC_STATUS_FAILED
);
222 DCHECK(remote_details
.file_kind() == FILE_KIND_FILE
||
223 remote_details
.file_kind() == FILE_KIND_FOLDER
);
225 if (synced_details
.title() != remote_details
.title()) {
226 // Handle rename as deletion + addition.
227 util::Log(logging::LOG_VERBOSE
, FROM_HERE
,
228 "[Remote -> Local]: Detected file rename.");
229 Prepare(base::Bind(&RemoteToLocalSyncer::DidPrepareForDeletion
,
230 weak_ptr_factory_
.GetWeakPtr(), callback
));
233 DCHECK_EQ(synced_details
.title(), remote_details
.title());
235 FileTracker parent_tracker
;
236 if (!metadata_database()->FindTrackerByTrackerID(
237 dirty_tracker_
->parent_tracker_id(), &parent_tracker
)) {
238 LOG(ERROR
) << "Missing parent tracker for a non sync-root tracker: "
239 << dirty_tracker_
->file_id();
241 callback
.Run(SYNC_STATUS_FAILED
);
245 if (!HasFolderAsParent(remote_details
, parent_tracker
.file_id())) {
246 // Handle reorganize as deletion + addition.
247 util::Log(logging::LOG_VERBOSE
, FROM_HERE
,
248 "[Remote -> Local]: Detected file reorganize.");
249 Prepare(base::Bind(&RemoteToLocalSyncer::DidPrepareForDeletion
,
250 weak_ptr_factory_
.GetWeakPtr(), callback
));
254 if (synced_details
.file_kind() == FILE_KIND_FILE
) {
255 if (synced_details
.md5() != remote_details
.md5()) {
256 util::Log(logging::LOG_VERBOSE
, FROM_HERE
,
257 "[Remote -> Local]: Detected file content update.");
258 HandleContentUpdate(callback
);
262 DCHECK_EQ(FILE_KIND_FOLDER
, synced_details
.file_kind());
263 if (synced_details
.missing()) {
264 util::Log(logging::LOG_VERBOSE
, FROM_HERE
,
265 "[Remote -> Local]: Detected folder update.");
266 HandleFolderUpdate(callback
);
269 if (dirty_tracker_
->needs_folder_listing()) {
270 util::Log(logging::LOG_VERBOSE
, FROM_HERE
,
271 "[Remote -> Local]: Needs listing folder.");
272 ListFolderContent(callback
);
275 callback
.Run(SYNC_STATUS_OK
);
279 util::Log(logging::LOG_VERBOSE
, FROM_HERE
,
280 "[Remote -> Local]: Trivial file change.");
281 callback
.Run(SYNC_STATUS_OK
);
284 void RemoteToLocalSyncer::HandleMissingRemoteMetadata(
285 const SyncStatusCallback
& callback
) {
286 DCHECK(dirty_tracker_
);
288 drive_service()->GetResourceEntry(
289 dirty_tracker_
->file_id(),
290 base::Bind(&RemoteToLocalSyncer::DidGetRemoteMetadata
,
291 weak_ptr_factory_
.GetWeakPtr(),
295 void RemoteToLocalSyncer::DidGetRemoteMetadata(
296 const SyncStatusCallback
& callback
,
297 google_apis::GDataErrorCode error
,
298 scoped_ptr
<google_apis::ResourceEntry
> entry
) {
299 SyncStatusCode status
= GDataErrorCodeToSyncStatusCode(error
);
300 if (status
!= SYNC_STATUS_OK
&&
301 error
!= google_apis::HTTP_NOT_FOUND
) {
302 callback
.Run(status
);
306 if (error
== google_apis::HTTP_NOT_FOUND
) {
307 metadata_database()->UpdateByDeletedRemoteFile(
308 dirty_tracker_
->file_id(), callback
);
314 callback
.Run(SYNC_STATUS_FAILED
);
318 metadata_database()->UpdateByFileResource(
319 *drive::util::ConvertResourceEntryToFileResource(*entry
),
320 base::Bind(&RemoteToLocalSyncer::DidUpdateDatabaseForRemoteMetadata
,
321 weak_ptr_factory_
.GetWeakPtr(), callback
));
324 void RemoteToLocalSyncer::DidUpdateDatabaseForRemoteMetadata(
325 const SyncStatusCallback
& callback
,
326 SyncStatusCode status
) {
327 if (status
!= SYNC_STATUS_OK
) {
328 callback
.Run(status
);
332 callback
.Run(SYNC_STATUS_RETRY
); // Do not update |dirty_tracker_|.
335 void RemoteToLocalSyncer::DidPrepareForAddOrUpdateFile(
336 const SyncStatusCallback
& callback
,
337 SyncStatusCode status
) {
338 if (status
!= SYNC_STATUS_OK
) {
339 callback
.Run(status
);
343 DCHECK(url_
.is_valid());
344 DCHECK(local_metadata_
);
345 DCHECK(local_changes_
);
347 // Check if the local file exists.
348 if (local_metadata_
->file_type
== SYNC_FILE_TYPE_UNKNOWN
||
349 (!local_changes_
->empty() && local_changes_
->back().IsDelete())) {
350 sync_action_
= SYNC_ACTION_ADDED
;
351 // Missing local file case.
352 // Download the file and add it to local as a new file.
353 DownloadFile(callback
);
357 DCHECK(local_changes_
->empty() || local_changes_
->back().IsAddOrUpdate());
358 if (local_changes_
->empty()) {
359 if (local_metadata_
->file_type
== SYNC_FILE_TYPE_FILE
) {
360 sync_action_
= SYNC_ACTION_UPDATED
;
361 // Download the file and overwrite the existing local file.
362 DownloadFile(callback
);
366 DCHECK_EQ(SYNC_FILE_TYPE_DIRECTORY
, local_metadata_
->file_type
);
368 // Got a remote regular file modification for existing local folder.
369 // Our policy prioritize folders in this case.
370 // Lower the priority of the tracker to prevent repeated remote sync to the
371 // same tracker, and let local-to-remote sync phase process this change.
372 metadata_database()->LowerTrackerPriority(dirty_tracker_
->tracker_id());
373 remote_change_processor()->RecordFakeLocalChange(
375 FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE
,
376 local_metadata_
->file_type
),
381 DCHECK(local_changes_
->back().IsAddOrUpdate());
383 // Do nothing for the change now, and handle this in LocalToRemoteSync phase.
385 // Lower the priority of the tracker to prevent repeated remote sync to the
387 metadata_database()->LowerTrackerPriority(dirty_tracker_
->tracker_id());
388 callback
.Run(SYNC_STATUS_RETRY
);
391 void RemoteToLocalSyncer::HandleFolderUpdate(
392 const SyncStatusCallback
& callback
) {
393 DCHECK(dirty_tracker_
);
394 DCHECK(dirty_tracker_
->active());
395 DCHECK(!HasDisabledAppRoot(metadata_database(), *dirty_tracker_
));
397 DCHECK(remote_metadata_
);
398 DCHECK(remote_metadata_
->has_details());
399 DCHECK(!remote_metadata_
->details().missing());
400 DCHECK_EQ(FILE_KIND_FOLDER
, remote_metadata_
->details().file_kind());
402 Prepare(base::Bind(&RemoteToLocalSyncer::DidPrepareForFolderUpdate
,
403 weak_ptr_factory_
.GetWeakPtr(), callback
));
406 void RemoteToLocalSyncer::DidPrepareForFolderUpdate(
407 const SyncStatusCallback
& callback
,
408 SyncStatusCode status
) {
409 if (status
!= SYNC_STATUS_OK
) {
410 callback
.Run(status
);
414 DCHECK(url_
.is_valid());
415 DCHECK(local_metadata_
);
416 DCHECK(local_changes_
);
418 // Check if the local file exists.
419 if (local_metadata_
->file_type
== SYNC_FILE_TYPE_UNKNOWN
||
420 (!local_changes_
->empty() && local_changes_
->back().IsDelete())) {
421 sync_action_
= SYNC_ACTION_ADDED
;
422 // No local file exists at the path.
423 CreateFolder(callback
);
427 if (local_metadata_
->file_type
== SYNC_FILE_TYPE_DIRECTORY
) {
428 // There already exists a folder, nothing left to do.
429 if (dirty_tracker_
->needs_folder_listing() &&
430 !dirty_tracker_
->synced_details().missing()) {
431 ListFolderContent(callback
);
433 callback
.Run(SYNC_STATUS_OK
);
438 DCHECK_EQ(SYNC_FILE_TYPE_FILE
, local_metadata_
->file_type
);
439 sync_action_
= SYNC_ACTION_ADDED
;
440 // Got a remote folder for existing local file.
441 // Our policy prioritize folders in this case.
442 CreateFolder(callback
);
445 void RemoteToLocalSyncer::HandleSyncRootDeletion(
446 const SyncStatusCallback
& callback
) {
447 sync_root_deletion_
= true;
448 callback
.Run(SYNC_STATUS_OK
);
451 void RemoteToLocalSyncer::HandleDeletion(
452 const SyncStatusCallback
& callback
) {
453 DCHECK(dirty_tracker_
);
454 DCHECK(dirty_tracker_
->active());
455 DCHECK(!HasDisabledAppRoot(metadata_database(), *dirty_tracker_
));
456 DCHECK(dirty_tracker_
->has_synced_details());
457 DCHECK(!dirty_tracker_
->synced_details().missing());
459 DCHECK(remote_metadata_
);
460 DCHECK(remote_metadata_
->has_details());
461 DCHECK(remote_metadata_
->details().missing());
463 Prepare(base::Bind(&RemoteToLocalSyncer::DidPrepareForDeletion
,
464 weak_ptr_factory_
.GetWeakPtr(), callback
));
467 void RemoteToLocalSyncer::DidPrepareForDeletion(
468 const SyncStatusCallback
& callback
,
469 SyncStatusCode status
) {
470 if (status
!= SYNC_STATUS_OK
) {
471 callback
.Run(status
);
475 DCHECK(url_
.is_valid());
476 DCHECK(local_metadata_
);
477 DCHECK(local_changes_
);
479 // Check if the local file exists.
480 if (local_metadata_
->file_type
== SYNC_FILE_TYPE_UNKNOWN
||
481 (!local_changes_
->empty() && local_changes_
->back().IsDelete())) {
482 // No local file exists at the path.
483 callback
.Run(SYNC_STATUS_OK
);
487 DCHECK(local_changes_
->empty() || local_changes_
->back().IsAddOrUpdate());
488 if (local_changes_
->empty()) {
489 sync_action_
= SYNC_ACTION_DELETED
;
490 DeleteLocalFile(callback
);
494 DCHECK(local_changes_
->back().IsAddOrUpdate());
495 // File is remotely deleted and locally updated.
496 // Ignore the remote deletion and handle it as if applied successfully.
497 callback
.Run(SYNC_STATUS_OK
);
500 void RemoteToLocalSyncer::HandleContentUpdate(
501 const SyncStatusCallback
& callback
) {
502 DCHECK(dirty_tracker_
);
503 DCHECK(dirty_tracker_
->active());
504 DCHECK(!HasDisabledAppRoot(metadata_database(), *dirty_tracker_
));
505 DCHECK(dirty_tracker_
->has_synced_details());
506 DCHECK_EQ(FILE_KIND_FILE
, dirty_tracker_
->synced_details().file_kind());
508 DCHECK(remote_metadata_
);
509 DCHECK(remote_metadata_
->has_details());
510 DCHECK(!remote_metadata_
->details().missing());
512 DCHECK_NE(dirty_tracker_
->synced_details().md5(),
513 remote_metadata_
->details().md5());
515 Prepare(base::Bind(&RemoteToLocalSyncer::DidPrepareForAddOrUpdateFile
,
516 weak_ptr_factory_
.GetWeakPtr(), callback
));
519 void RemoteToLocalSyncer::ListFolderContent(
520 const SyncStatusCallback
& callback
) {
521 DCHECK(dirty_tracker_
);
522 DCHECK(dirty_tracker_
->active());
523 DCHECK(!HasDisabledAppRoot(metadata_database(), *dirty_tracker_
));
524 DCHECK(dirty_tracker_
->has_synced_details());
525 DCHECK(!dirty_tracker_
->synced_details().missing());
526 DCHECK_EQ(FILE_KIND_FOLDER
, dirty_tracker_
->synced_details().file_kind());
527 DCHECK(dirty_tracker_
->needs_folder_listing());
529 DCHECK(remote_metadata_
);
530 DCHECK(remote_metadata_
->has_details());
531 DCHECK(!remote_metadata_
->details().missing());
533 // TODO(tzik): Replace this call with ChildList version.
534 drive_service()->GetResourceListInDirectory(
535 dirty_tracker_
->file_id(),
536 base::Bind(&RemoteToLocalSyncer::DidListFolderContent
,
537 weak_ptr_factory_
.GetWeakPtr(),
539 base::Passed(make_scoped_ptr(new FileIDList
))));
542 void RemoteToLocalSyncer::DidListFolderContent(
543 const SyncStatusCallback
& callback
,
544 scoped_ptr
<FileIDList
> children
,
545 google_apis::GDataErrorCode error
,
546 scoped_ptr
<google_apis::ResourceList
> resource_list
) {
547 SyncStatusCode status
= GDataErrorCodeToSyncStatusCode(error
);
548 if (status
!= SYNC_STATUS_OK
) {
549 callback
.Run(status
);
553 if (!resource_list
) {
555 callback
.Run(SYNC_STATUS_FAILED
);
559 children
->reserve(children
->size() + resource_list
->entries().size());
560 for (ScopedVector
<google_apis::ResourceEntry
>::const_iterator itr
=
561 resource_list
->entries().begin();
562 itr
!= resource_list
->entries().end();
564 children
->push_back((*itr
)->resource_id());
568 if (resource_list
->GetNextFeedURL(&next_feed
)) {
569 drive_service()->GetRemainingFileList(
571 base::Bind(&RemoteToLocalSyncer::DidListFolderContent
,
572 weak_ptr_factory_
.GetWeakPtr(),
573 callback
, base::Passed(&children
)));
577 metadata_database()->PopulateFolderByChildList(
578 dirty_tracker_
->file_id(), *children
, callback
);
581 void RemoteToLocalSyncer::SyncCompleted(const SyncStatusCallback
& callback
,
582 SyncStatusCode status
) {
583 util::Log(logging::LOG_VERBOSE
, FROM_HERE
,
584 "[Remote -> Local]: Finished: action=%s, tracker=%" PRId64
586 SyncActionToString(sync_action_
), dirty_tracker_
->tracker_id(),
587 SyncStatusCodeToString(status
));
589 if (sync_root_deletion_
) {
590 callback
.Run(SYNC_STATUS_OK
);
594 if (status
== SYNC_STATUS_RETRY
) {
595 callback
.Run(SYNC_STATUS_OK
);
599 if (status
!= SYNC_STATUS_OK
) {
600 callback
.Run(status
);
604 DCHECK(dirty_tracker_
);
605 DCHECK(remote_metadata_
);
606 DCHECK(remote_metadata_
->has_details());
608 FileDetails updated_details
= remote_metadata_
->details();
609 if (!dirty_tracker_
->active() ||
610 HasDisabledAppRoot(metadata_database(), *dirty_tracker_
)) {
611 // Operations for an inactive tracker don't update file content.
612 if (dirty_tracker_
->has_synced_details())
613 updated_details
.set_md5(dirty_tracker_
->synced_details().md5());
614 if (!dirty_tracker_
->active()) {
615 // Keep missing true, as the change hasn't been synced to local.
616 updated_details
.clear_md5();
617 updated_details
.set_missing(true);
620 metadata_database()->UpdateTracker(dirty_tracker_
->tracker_id(),
625 void RemoteToLocalSyncer::FinalizeSync(const SyncStatusCallback
& callback
,
626 SyncStatusCode status
) {
628 remote_change_processor()->FinalizeRemoteSync(
629 url_
, false /* clear_local_change */, base::Bind(callback
, status
));
633 callback
.Run(status
);
636 void RemoteToLocalSyncer::Prepare(const SyncStatusCallback
& callback
) {
637 bool should_success
= BuildFileSystemURL(
638 metadata_database(), *dirty_tracker_
, &url_
);
639 DCHECK(should_success
);
640 DCHECK(url_
.is_valid());
641 remote_change_processor()->PrepareForProcessRemoteChange(
643 base::Bind(&RemoteToLocalSyncer::DidPrepare
,
644 weak_ptr_factory_
.GetWeakPtr(),
648 void RemoteToLocalSyncer::DidPrepare(const SyncStatusCallback
& callback
,
649 SyncStatusCode status
,
650 const SyncFileMetadata
& local_metadata
,
651 const FileChangeList
& local_changes
) {
652 if (status
!= SYNC_STATUS_OK
) {
653 callback
.Run(status
);
658 local_metadata_
.reset(new SyncFileMetadata(local_metadata
));
659 local_changes_
.reset(new FileChangeList(local_changes
));
661 callback
.Run(status
);
664 void RemoteToLocalSyncer::DeleteLocalFile(const SyncStatusCallback
& callback
) {
665 remote_change_processor()->ApplyRemoteChange(
666 FileChange(FileChange::FILE_CHANGE_DELETE
, SYNC_FILE_TYPE_UNKNOWN
),
672 void RemoteToLocalSyncer::DownloadFile(const SyncStatusCallback
& callback
) {
673 base::PostTaskAndReplyWithResult(
674 sync_context_
->GetBlockingTaskRunner(), FROM_HERE
,
675 base::Bind(&sync_file_system::drive_backend::CreateTemporaryFile
,
676 make_scoped_refptr(sync_context_
->GetBlockingTaskRunner())),
677 base::Bind(&RemoteToLocalSyncer::DidCreateTemporaryFileForDownload
,
678 weak_ptr_factory_
.GetWeakPtr(), callback
));
681 void RemoteToLocalSyncer::DidCreateTemporaryFileForDownload(
682 const SyncStatusCallback
& callback
,
683 webkit_blob::ScopedFile file
) {
684 base::FilePath path
= file
.path();
685 drive_service()->DownloadFile(
686 path
, remote_metadata_
->file_id(),
687 base::Bind(&RemoteToLocalSyncer::DidDownloadFile
,
688 weak_ptr_factory_
.GetWeakPtr(),
689 callback
, base::Passed(&file
)),
690 google_apis::GetContentCallback(),
691 google_apis::ProgressCallback());
694 void RemoteToLocalSyncer::DidDownloadFile(const SyncStatusCallback
& callback
,
695 webkit_blob::ScopedFile file
,
696 google_apis::GDataErrorCode error
,
697 const base::FilePath
&) {
698 SyncStatusCode status
= GDataErrorCodeToSyncStatusCode(error
);
699 if (status
!= SYNC_STATUS_OK
) {
700 callback
.Run(status
);
704 base::FilePath path
= file
.path();
705 base::PostTaskAndReplyWithResult(
706 sync_context_
->GetBlockingTaskRunner(), FROM_HERE
,
707 base::Bind(&drive::util::GetMd5Digest
, path
),
708 base::Bind(&RemoteToLocalSyncer::DidCalculateMD5ForDownload
,
709 weak_ptr_factory_
.GetWeakPtr(),
710 callback
, base::Passed(&file
)));
713 void RemoteToLocalSyncer::DidCalculateMD5ForDownload(
714 const SyncStatusCallback
& callback
,
715 webkit_blob::ScopedFile file
,
716 const std::string
& md5
) {
718 callback
.Run(SYNC_FILE_ERROR_NOT_FOUND
);
722 if (md5
!= remote_metadata_
->details().md5()) {
723 // File has been modified since last metadata retrieval.
725 // Lower the priority of the tracker to prevent repeated remote sync to the
727 metadata_database()->LowerTrackerPriority(dirty_tracker_
->tracker_id());
728 callback
.Run(SYNC_STATUS_RETRY
);
732 base::FilePath path
= file
.path();
733 remote_change_processor()->ApplyRemoteChange(
734 FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE
, SYNC_FILE_TYPE_FILE
),
736 base::Bind(&RemoteToLocalSyncer::DidApplyDownload
,
737 weak_ptr_factory_
.GetWeakPtr(),
738 callback
, base::Passed(&file
)));
741 void RemoteToLocalSyncer::DidApplyDownload(const SyncStatusCallback
& callback
,
742 webkit_blob::ScopedFile
,
743 SyncStatusCode status
) {
744 if (status
!= SYNC_STATUS_OK
)
745 metadata_database()->LowerTrackerPriority(dirty_tracker_
->tracker_id());
746 callback
.Run(status
);
749 void RemoteToLocalSyncer::CreateFolder(const SyncStatusCallback
& callback
) {
750 remote_change_processor()->ApplyRemoteChange(
751 FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE
,
752 SYNC_FILE_TYPE_DIRECTORY
),
753 base::FilePath(), url_
,
757 drive::DriveServiceInterface
* RemoteToLocalSyncer::drive_service() {
758 return sync_context_
->GetDriveService();
761 MetadataDatabase
* RemoteToLocalSyncer::metadata_database() {
762 return sync_context_
->GetMetadataDatabase();
765 RemoteChangeProcessor
* RemoteToLocalSyncer::remote_change_processor() {
766 DCHECK(sync_context_
->GetRemoteChangeProcessor());
767 return sync_context_
->GetRemoteChangeProcessor();
770 } // namespace drive_backend
771 } // namespace sync_file_system