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/local_to_remote_syncer.h"
10 #include "base/callback.h"
11 #include "base/format_macros.h"
12 #include "base/location.h"
13 #include "base/logging.h"
14 #include "base/sequenced_task_runner.h"
15 #include "base/strings/stringprintf.h"
16 #include "base/task_runner_util.h"
17 #include "chrome/browser/drive/drive_api_util.h"
18 #include "chrome/browser/drive/drive_service_interface.h"
19 #include "chrome/browser/drive/drive_uploader.h"
20 #include "chrome/browser/sync_file_system/drive_backend/callback_helper.h"
21 #include "chrome/browser/sync_file_system/drive_backend/drive_backend_util.h"
22 #include "chrome/browser/sync_file_system/drive_backend/folder_creator.h"
23 #include "chrome/browser/sync_file_system/drive_backend/metadata_database.h"
24 #include "chrome/browser/sync_file_system/drive_backend/metadata_database.pb.h"
25 #include "chrome/browser/sync_file_system/drive_backend/sync_engine_context.h"
26 #include "chrome/browser/sync_file_system/drive_backend/sync_task_manager.h"
27 #include "chrome/browser/sync_file_system/drive_backend/sync_task_token.h"
28 #include "chrome/browser/sync_file_system/logger.h"
29 #include "google_apis/drive/drive_api_parser.h"
30 #include "webkit/common/fileapi/file_system_util.h"
32 namespace sync_file_system
{
33 namespace drive_backend
{
37 scoped_ptr
<FileTracker
> FindTrackerByID(MetadataDatabase
* metadata_database
,
39 scoped_ptr
<FileTracker
> tracker(new FileTracker
);
40 if (metadata_database
->FindTrackerByTrackerID(tracker_id
, tracker
.get()))
41 return tracker
.Pass();
42 return scoped_ptr
<FileTracker
>();
45 bool GetKnownChangeID(MetadataDatabase
* metadata_database
,
46 const std::string
& file_id
,
48 FileMetadata remote_file_metadata
;
49 if (!metadata_database
->FindFileByFileID(file_id
, &remote_file_metadata
))
51 *change_id
= remote_file_metadata
.details().change_id();
55 bool IsLocalFileMissing(const SyncFileMetadata
& local_metadata
,
56 const FileChange
& local_change
) {
57 return local_metadata
.file_type
== SYNC_FILE_TYPE_UNKNOWN
||
58 local_change
.IsDelete();
63 LocalToRemoteSyncer::LocalToRemoteSyncer(SyncEngineContext
* sync_context
,
64 const SyncFileMetadata
& local_metadata
,
65 const FileChange
& local_change
,
66 const base::FilePath
& local_path
,
67 const fileapi::FileSystemURL
& url
)
68 : sync_context_(sync_context
),
69 local_change_(local_change
),
70 local_is_missing_(IsLocalFileMissing(local_metadata
, local_change
)),
71 local_path_(local_path
),
73 sync_action_(SYNC_ACTION_NONE
),
74 remote_file_change_id_(0),
75 retry_on_success_(false),
76 needs_remote_change_listing_(false),
77 weak_ptr_factory_(this) {
78 DCHECK(local_is_missing_
||
79 local_change
.file_type() == local_metadata
.file_type
)
80 << local_change
.DebugString() << " metadata:" << local_metadata
.file_type
;
83 LocalToRemoteSyncer::~LocalToRemoteSyncer() {
86 void LocalToRemoteSyncer::RunPreflight(scoped_ptr
<SyncTaskToken
> token
) {
87 token
->InitializeTaskLog("Local -> Remote");
89 if (!IsContextReady()) {
90 token
->RecordLog("Context not ready.");
92 SyncTaskManager::NotifyTaskDone(token
.Pass(), SYNC_STATUS_FAILED
);
96 token
->RecordLog(base::StringPrintf(
97 "Start: %s on %s@%s %s",
98 local_change_
.DebugString().c_str(),
99 url_
.path().AsUTF8Unsafe().c_str(),
100 url_
.origin().host().c_str(),
101 local_is_missing_
? "(missing)" : ""));
103 if (local_is_missing_
&& !local_change_
.IsDelete()) {
104 // Stray file, we can just return.
105 token
->RecordLog("Missing file for non-delete change.");
106 SyncTaskManager::NotifyTaskDone(token
.Pass(), SYNC_STATUS_OK
);
110 std::string app_id
= url_
.origin().host();
111 base::FilePath path
= url_
.path();
113 scoped_ptr
<FileTracker
> active_ancestor_tracker(new FileTracker
);
114 base::FilePath active_ancestor_path
;
115 if (!metadata_database()->FindNearestActiveAncestor(
117 active_ancestor_tracker
.get(), &active_ancestor_path
)) {
118 // The app is disabled or not registered.
119 token
->RecordLog("App is disabled or not registered");
120 SyncTaskManager::NotifyTaskDone(token
.Pass(), SYNC_STATUS_UNKNOWN_ORIGIN
);
123 DCHECK(active_ancestor_tracker
->active());
124 DCHECK(active_ancestor_tracker
->has_synced_details());
125 const FileDetails
& active_ancestor_details
=
126 active_ancestor_tracker
->synced_details();
128 // TODO(tzik): Consider handling
129 // active_ancestor_tracker->synced_details().missing() case.
131 DCHECK(active_ancestor_details
.file_kind() == FILE_KIND_FILE
||
132 active_ancestor_details
.file_kind() == FILE_KIND_FOLDER
);
134 base::FilePath missing_entries
;
135 if (active_ancestor_path
.empty()) {
136 missing_entries
= path
;
137 } else if (active_ancestor_path
!= path
) {
138 if (!active_ancestor_path
.AppendRelativePath(path
, &missing_entries
)) {
140 token
->RecordLog(base::StringPrintf(
141 "Detected invalid ancestor: %s",
142 active_ancestor_path
.value().c_str()));
143 SyncTaskManager::NotifyTaskDone(token
.Pass(), SYNC_STATUS_FAILED
);
148 std::vector
<base::FilePath::StringType
> missing_components
;
149 fileapi::VirtualPath::GetComponents(missing_entries
, &missing_components
);
151 if (!missing_components
.empty()) {
152 if (local_is_missing_
) {
153 token
->RecordLog("Both local and remote are marked missing");
154 // !IsDelete() but SYNC_FILE_TYPE_UNKNOWN could happen when a file is
155 // deleted by recursive deletion (which is not recorded by tracker)
156 // but there're remaining changes for the same file in the tracker.
158 // Local file is deleted and remote file is missing, already deleted or
159 // not yet synced. There is nothing to do for the file.
160 SyncTaskManager::NotifyTaskDone(token
.Pass(), SYNC_STATUS_OK
);
165 if (missing_components
.size() > 1) {
166 // The original target doesn't have remote file and parent.
167 // Try creating the parent first.
168 if (active_ancestor_details
.file_kind() == FILE_KIND_FOLDER
) {
169 remote_parent_folder_tracker_
= active_ancestor_tracker
.Pass();
170 target_path_
= active_ancestor_path
.Append(missing_components
[0]);
171 token
->RecordLog("Detected missing parent folder.");
173 retry_on_success_
= true;
174 MoveToBackground(base::Bind(&LocalToRemoteSyncer::CreateRemoteFolder
,
175 weak_ptr_factory_
.GetWeakPtr()),
180 DCHECK(active_ancestor_details
.file_kind() == FILE_KIND_FILE
);
181 remote_parent_folder_tracker_
=
182 FindTrackerByID(metadata_database(),
183 active_ancestor_tracker
->parent_tracker_id());
184 remote_file_tracker_
= active_ancestor_tracker
.Pass();
185 target_path_
= active_ancestor_path
;
186 token
->RecordLog("Detected non-folder file in its path.");
188 retry_on_success_
= true;
189 MoveToBackground(base::Bind(&LocalToRemoteSyncer::DeleteRemoteFile
,
190 weak_ptr_factory_
.GetWeakPtr()),
195 if (missing_components
.empty()) {
196 // The original target has remote active file/folder.
197 remote_parent_folder_tracker_
=
198 FindTrackerByID(metadata_database(),
199 active_ancestor_tracker
->parent_tracker_id());
200 remote_file_tracker_
= active_ancestor_tracker
.Pass();
201 target_path_
= url_
.path();
202 DCHECK(target_path_
== active_ancestor_path
);
204 if (remote_file_tracker_
->dirty()) {
205 token
->RecordLog(base::StringPrintf(
206 "Detected conflicting dirty tracker:%" PRId64
,
207 remote_file_tracker_
->tracker_id()));
208 // Both local and remote file has pending modification.
209 HandleConflict(token
.Pass());
213 // Non-conflicting file/folder update case.
214 HandleExistingRemoteFile(token
.Pass());
218 DCHECK(local_change_
.IsAddOrUpdate());
219 DCHECK_EQ(1u, missing_components
.size());
220 // The original target has remote parent folder and doesn't have remote active
222 // Upload the file as a new file or create a folder.
223 remote_parent_folder_tracker_
= active_ancestor_tracker
.Pass();
224 target_path_
= url_
.path();
225 DCHECK(target_path_
== active_ancestor_path
.Append(missing_components
[0]));
226 if (local_change_
.file_type() == SYNC_FILE_TYPE_FILE
) {
227 token
->RecordLog("Detected a new file.");
228 MoveToBackground(base::Bind(&LocalToRemoteSyncer::UploadNewFile
,
229 weak_ptr_factory_
.GetWeakPtr()),
234 token
->RecordLog("Detected a new folder.");
235 MoveToBackground(base::Bind(&LocalToRemoteSyncer::CreateRemoteFolder
,
236 weak_ptr_factory_
.GetWeakPtr()),
240 void LocalToRemoteSyncer::MoveToBackground(const Continuation
& continuation
,
241 scoped_ptr
<SyncTaskToken
> token
) {
242 scoped_ptr
<BlockingFactor
> blocker(new BlockingFactor
);
243 blocker
->app_id
= url_
.origin().host();
244 blocker
->paths
.push_back(target_path_
);
246 if (remote_file_tracker_
) {
247 if (!GetKnownChangeID(metadata_database(),
248 remote_file_tracker_
->file_id(),
249 &remote_file_change_id_
)) {
251 SyncCompleted(token
.Pass(), SYNC_STATUS_FAILED
);
255 blocker
->tracker_ids
.push_back(remote_file_tracker_
->tracker_id());
256 blocker
->file_ids
.push_back(remote_file_tracker_
->file_id());
259 // Run current task as a background task with |blocker|.
260 // After the invocation of ContinueAsBackgroundTask
261 SyncTaskManager::UpdateBlockingFactor(
262 token
.Pass(), blocker
.Pass(),
263 base::Bind(&LocalToRemoteSyncer::ContinueAsBackgroundTask
,
264 weak_ptr_factory_
.GetWeakPtr(),
268 void LocalToRemoteSyncer::ContinueAsBackgroundTask(
269 const Continuation
& continuation
,
270 scoped_ptr
<SyncTaskToken
> token
) {
271 // The SyncTask runs as a background task beyond this point.
272 // Note that any task can run between MoveToBackground() and
273 // ContinueAsBackgroundTask(), so we need to make sure other tasks didn't
274 // affect to the current LocalToRemoteSyncer task.
276 // - For RemoteToLocalSyncer, it doesn't actually run beyond
277 // PrepareForProcessRemoteChange() since it should be blocked in
278 // LocalFileSyncService.
279 // - For ListChangesTask, it may update FileMetatada together with |change_id|
280 // and may delete FileTracker. So, ensure |change_id| is not changed and
281 // check if FileTracker still exists.
282 // - For UninstallAppTask, it may also delete FileMetadata and FileTracker.
283 // And also, check if FileTracker still exists.
284 // - Others, SyncEngineInitializer and RegisterAppTask doesn't affect to
285 // LocalToRemoteSyncer.
286 if (remote_file_tracker_
) {
287 int64 latest_change_id
= 0;
288 if (!GetKnownChangeID(metadata_database(),
289 remote_file_tracker_
->file_id(),
290 &latest_change_id
) ||
291 latest_change_id
> remote_file_change_id_
) {
292 SyncCompleted(token
.Pass(), SYNC_STATUS_RETRY
);
296 if (!metadata_database()->FindTrackerByTrackerID(
297 remote_file_tracker_
->tracker_id(), NULL
)) {
298 SyncCompleted(token
.Pass(), SYNC_STATUS_RETRY
);
303 continuation
.Run(token
.Pass());
306 void LocalToRemoteSyncer::SyncCompleted(scoped_ptr
<SyncTaskToken
> token
,
307 SyncStatusCode status
) {
308 if (status
== SYNC_STATUS_OK
&& retry_on_success_
)
309 status
= SYNC_STATUS_RETRY
;
311 if (needs_remote_change_listing_
)
312 status
= SYNC_STATUS_FILE_BUSY
;
314 token
->RecordLog(base::StringPrintf(
315 "Finished: action=%s, status=%s for %s@%s",
316 SyncActionToString(sync_action_
),
317 SyncStatusCodeToString(status
),
318 target_path_
.AsUTF8Unsafe().c_str(),
319 url_
.origin().host().c_str()));
321 SyncTaskManager::NotifyTaskDone(token
.Pass(), status
);
324 void LocalToRemoteSyncer::HandleConflict(scoped_ptr
<SyncTaskToken
> token
) {
325 DCHECK(remote_file_tracker_
);
326 DCHECK(remote_file_tracker_
->has_synced_details());
327 DCHECK(remote_file_tracker_
->active());
328 DCHECK(remote_file_tracker_
->dirty());
330 if (local_is_missing_
) {
331 SyncCompleted(token
.Pass(), SYNC_STATUS_OK
);
335 if (local_change_
.IsFile()) {
336 // Upload the conflicting file as a new file and let ConflictResolver
338 MoveToBackground(base::Bind(&LocalToRemoteSyncer::UploadNewFile
,
339 weak_ptr_factory_
.GetWeakPtr()),
344 DCHECK(local_change_
.IsDirectory());
345 // Check if we can reuse the remote folder.
346 FileMetadata remote_file_metadata
;
347 if (!metadata_database()->FindFileByFileID(
348 remote_file_tracker_
->file_id(), &remote_file_metadata
)) {
350 MoveToBackground(base::Bind(&LocalToRemoteSyncer::CreateRemoteFolder
,
351 weak_ptr_factory_
.GetWeakPtr()),
356 const FileDetails
& remote_details
= remote_file_metadata
.details();
357 base::FilePath title
= fileapi::VirtualPath::BaseName(target_path_
);
358 if (!remote_details
.missing() &&
359 remote_details
.file_kind() == FILE_KIND_FOLDER
&&
360 remote_details
.title() == title
.AsUTF8Unsafe() &&
361 HasFileAsParent(remote_details
,
362 remote_parent_folder_tracker_
->file_id())) {
365 base::Bind(&LocalToRemoteSyncer::UpdateTrackerForReusedFolder
,
366 weak_ptr_factory_
.GetWeakPtr(),
372 MoveToBackground(base::Bind(&LocalToRemoteSyncer::CreateRemoteFolder
,
373 weak_ptr_factory_
.GetWeakPtr()),
377 void LocalToRemoteSyncer::UpdateTrackerForReusedFolder(
378 const FileDetails
& details
,
379 scoped_ptr
<SyncTaskToken
> token
) {
380 metadata_database()->UpdateTracker(
381 remote_file_tracker_
->tracker_id(), details
,
382 base::Bind(&LocalToRemoteSyncer::SyncCompleted
,
383 weak_ptr_factory_
.GetWeakPtr(),
384 base::Passed(&token
)));
387 void LocalToRemoteSyncer::HandleExistingRemoteFile(
388 scoped_ptr
<SyncTaskToken
> token
) {
389 DCHECK(remote_file_tracker_
);
390 DCHECK(!remote_file_tracker_
->dirty());
391 DCHECK(remote_file_tracker_
->active());
392 DCHECK(remote_file_tracker_
->has_synced_details());
394 if (local_is_missing_
) {
395 // Local file deletion for existing remote file.
396 MoveToBackground(base::Bind(&LocalToRemoteSyncer::DeleteRemoteFile
,
397 weak_ptr_factory_
.GetWeakPtr()),
402 DCHECK(local_change_
.IsAddOrUpdate());
403 DCHECK(local_change_
.IsFile() || local_change_
.IsDirectory());
405 const FileDetails
& synced_details
= remote_file_tracker_
->synced_details();
406 DCHECK(synced_details
.file_kind() == FILE_KIND_FILE
||
407 synced_details
.file_kind() == FILE_KIND_FOLDER
);
408 if (local_change_
.IsFile()) {
409 if (synced_details
.file_kind() == FILE_KIND_FILE
) {
410 // Non-conflicting local file update to existing remote regular file.
411 MoveToBackground(base::Bind(&LocalToRemoteSyncer::UploadExistingFile
,
412 weak_ptr_factory_
.GetWeakPtr()),
417 DCHECK_EQ(FILE_KIND_FOLDER
, synced_details
.file_kind());
418 // Non-conflicting local file update to existing remote *folder*.
419 // Assuming this case as local folder deletion + local file creation, delete
420 // the remote folder and upload the file.
421 retry_on_success_
= true;
422 MoveToBackground(base::Bind(&LocalToRemoteSyncer::DeleteRemoteFile
,
423 weak_ptr_factory_
.GetWeakPtr()),
428 DCHECK(local_change_
.IsDirectory());
429 if (synced_details
.file_kind() == FILE_KIND_FILE
) {
430 // Non-conflicting local folder creation to existing remote *file*.
431 // Assuming this case as local file deletion + local folder creation, delete
432 // the remote file and create a remote folder.
433 retry_on_success_
= true;
434 MoveToBackground(base::Bind(&LocalToRemoteSyncer::DeleteRemoteFile
,
435 weak_ptr_factory_
.GetWeakPtr()),
440 // Non-conflicting local folder creation to existing remote folder.
441 DCHECK_EQ(FILE_KIND_FOLDER
, synced_details
.file_kind());
442 SyncCompleted(token
.Pass(), SYNC_STATUS_OK
);
445 void LocalToRemoteSyncer::DeleteRemoteFile(scoped_ptr
<SyncTaskToken
> token
) {
446 DCHECK(remote_file_tracker_
);
447 DCHECK(remote_file_tracker_
->has_synced_details());
449 sync_action_
= SYNC_ACTION_DELETED
;
450 drive_service()->DeleteResource(
451 remote_file_tracker_
->file_id(),
452 remote_file_tracker_
->synced_details().etag(),
453 base::Bind(&LocalToRemoteSyncer::DidDeleteRemoteFile
,
454 weak_ptr_factory_
.GetWeakPtr(), base::Passed(&token
)));
457 void LocalToRemoteSyncer::DidDeleteRemoteFile(
458 scoped_ptr
<SyncTaskToken
> token
,
459 google_apis::GDataErrorCode error
) {
460 SyncStatusCode status
= GDataErrorCodeToSyncStatusCode(error
);
461 if (status
!= SYNC_STATUS_OK
&&
462 error
!= google_apis::HTTP_NOT_FOUND
&&
463 error
!= google_apis::HTTP_PRECONDITION
&&
464 error
!= google_apis::HTTP_CONFLICT
) {
465 SyncCompleted(token
.Pass(), status
);
469 // Handle NOT_FOUND case as SUCCESS case.
470 // For PRECONDITION / CONFLICT case, the remote file is modified since the
471 // last sync completed. As our policy for deletion-modification conflict
472 // resolution, ignore the local deletion.
473 if (status
== SYNC_STATUS_OK
||
474 error
== google_apis::HTTP_NOT_FOUND
) {
475 metadata_database()->UpdateByDeletedRemoteFile(
476 remote_file_tracker_
->file_id(),
477 base::Bind(&LocalToRemoteSyncer::SyncCompleted
,
478 weak_ptr_factory_
.GetWeakPtr(), base::Passed(&token
)));
482 SyncCompleted(token
.Pass(), SYNC_STATUS_OK
);
485 void LocalToRemoteSyncer::UploadExistingFile(scoped_ptr
<SyncTaskToken
> token
) {
486 DCHECK(remote_file_tracker_
);
487 DCHECK(remote_file_tracker_
->has_synced_details());
488 DCHECK(sync_context_
->GetWorkerTaskRunner()->RunsTasksOnCurrentThread());
490 base::Callback
<void(const std::string
&)> did_calculate_callback
=
491 base::Bind(&LocalToRemoteSyncer::DidGetMD5ForUpload
,
492 weak_ptr_factory_
.GetWeakPtr(), base::Passed(&token
));
494 sync_context_
->GetFileTaskRunner()->PostTask(
496 CreateComposedFunction(
497 base::Bind(&drive::util::GetMd5Digest
, local_path_
),
498 RelayCallbackToTaskRunner(
499 sync_context_
->GetWorkerTaskRunner(), FROM_HERE
,
500 did_calculate_callback
)));
503 void LocalToRemoteSyncer::DidGetMD5ForUpload(
504 scoped_ptr
<SyncTaskToken
> token
,
505 const std::string
& local_file_md5
) {
506 if (local_file_md5
== remote_file_tracker_
->synced_details().md5()) {
507 // Local file is not changed.
508 SyncCompleted(token
.Pass(), SYNC_STATUS_OK
);
512 sync_action_
= SYNC_ACTION_UPDATED
;
514 drive::DriveUploader::UploadExistingFileOptions options
;
515 options
.etag
= remote_file_tracker_
->synced_details().etag();
516 drive_uploader()->UploadExistingFile(
517 remote_file_tracker_
->file_id(),
519 "application/octet_stream",
521 base::Bind(&LocalToRemoteSyncer::DidUploadExistingFile
,
522 weak_ptr_factory_
.GetWeakPtr(), base::Passed(&token
)),
523 google_apis::ProgressCallback());
526 void LocalToRemoteSyncer::DidUploadExistingFile(
527 scoped_ptr
<SyncTaskToken
> token
,
528 google_apis::GDataErrorCode error
,
530 scoped_ptr
<google_apis::FileResource
> entry
) {
531 if (error
== google_apis::HTTP_PRECONDITION
||
532 error
== google_apis::HTTP_CONFLICT
||
533 error
== google_apis::HTTP_NOT_FOUND
) {
534 // The remote file has unfetched remote change. Fetch latest metadata and
535 // update database with it.
536 // TODO(tzik): Consider adding local side low-priority dirtiness handling to
537 // handle this as ListChangesTask.
539 needs_remote_change_listing_
= true;
540 UpdateRemoteMetadata(
541 remote_file_tracker_
->file_id(),
546 SyncStatusCode status
= GDataErrorCodeToSyncStatusCode(error
);
547 if (status
!= SYNC_STATUS_OK
) {
548 SyncCompleted(token
.Pass(), status
);
554 SyncCompleted(token
.Pass(), SYNC_STATUS_FAILED
);
559 metadata_database()->UpdateByFileResource(
561 base::Bind(&LocalToRemoteSyncer::DidUpdateDatabaseForUploadExistingFile
,
562 weak_ptr_factory_
.GetWeakPtr(),
563 base::Passed(&token
)));
566 void LocalToRemoteSyncer::DidUpdateDatabaseForUploadExistingFile(
567 scoped_ptr
<SyncTaskToken
> token
,
568 SyncStatusCode status
) {
569 if (status
!= SYNC_STATUS_OK
) {
570 SyncCompleted(token
.Pass(), status
);
575 if (!metadata_database()->FindFileByFileID(
576 remote_file_tracker_
->file_id(), &file
)) {
578 SyncCompleted(token
.Pass(), SYNC_STATUS_FAILED
);
582 const FileDetails
& details
= file
.details();
583 base::FilePath title
= fileapi::VirtualPath::BaseName(target_path_
);
584 if (!details
.missing() &&
585 details
.file_kind() == FILE_KIND_FILE
&&
586 details
.title() == title
.AsUTF8Unsafe() &&
587 HasFileAsParent(details
,
588 remote_parent_folder_tracker_
->file_id())) {
589 metadata_database()->UpdateTracker(
590 remote_file_tracker_
->tracker_id(),
592 base::Bind(&LocalToRemoteSyncer::SyncCompleted
,
593 weak_ptr_factory_
.GetWeakPtr(),
594 base::Passed(&token
)));
598 SyncCompleted(token
.Pass(), SYNC_STATUS_RETRY
);
601 void LocalToRemoteSyncer::UpdateRemoteMetadata(
602 const std::string
& file_id
,
603 scoped_ptr
<SyncTaskToken
> token
) {
604 DCHECK(remote_file_tracker_
);
606 drive_service()->GetFileResource(
608 base::Bind(&LocalToRemoteSyncer::DidGetRemoteMetadata
,
609 weak_ptr_factory_
.GetWeakPtr(),
610 file_id
, base::Passed(&token
)));
613 void LocalToRemoteSyncer::DidGetRemoteMetadata(
614 const std::string
& file_id
,
615 scoped_ptr
<SyncTaskToken
> token
,
616 google_apis::GDataErrorCode error
,
617 scoped_ptr
<google_apis::FileResource
> entry
) {
618 DCHECK(sync_context_
->GetWorkerTaskRunner()->RunsTasksOnCurrentThread());
620 if (error
== google_apis::HTTP_NOT_FOUND
) {
621 retry_on_success_
= true;
622 metadata_database()->UpdateByDeletedRemoteFile(
624 base::Bind(&LocalToRemoteSyncer::SyncCompleted
,
625 weak_ptr_factory_
.GetWeakPtr(),
626 base::Passed(&token
)));
630 SyncStatusCode status
= GDataErrorCodeToSyncStatusCode(error
);
631 if (status
!= SYNC_STATUS_OK
) {
632 SyncCompleted(token
.Pass(), status
);
638 SyncCompleted(token
.Pass(), SYNC_STATUS_FAILED
);
642 retry_on_success_
= true;
643 metadata_database()->UpdateByFileResource(
645 base::Bind(&LocalToRemoteSyncer::SyncCompleted
,
646 weak_ptr_factory_
.GetWeakPtr(),
647 base::Passed(&token
)));
650 void LocalToRemoteSyncer::UploadNewFile(scoped_ptr
<SyncTaskToken
> token
) {
651 DCHECK(remote_parent_folder_tracker_
);
653 sync_action_
= SYNC_ACTION_ADDED
;
654 base::FilePath title
= fileapi::VirtualPath::BaseName(target_path_
);
655 drive_uploader()->UploadNewFile(
656 remote_parent_folder_tracker_
->file_id(),
658 title
.AsUTF8Unsafe(),
659 GetMimeTypeFromTitle(title
),
660 drive::DriveUploader::UploadNewFileOptions(),
661 base::Bind(&LocalToRemoteSyncer::DidUploadNewFile
,
662 weak_ptr_factory_
.GetWeakPtr(),
663 base::Passed(&token
)),
664 google_apis::ProgressCallback());
667 void LocalToRemoteSyncer::DidUploadNewFile(
668 scoped_ptr
<SyncTaskToken
> token
,
669 google_apis::GDataErrorCode error
,
670 const GURL
& upload_location
,
671 scoped_ptr
<google_apis::FileResource
> entry
) {
672 if (error
== google_apis::HTTP_NOT_FOUND
)
673 needs_remote_change_listing_
= true;
675 SyncStatusCode status
= GDataErrorCodeToSyncStatusCode(error
);
676 if (status
!= SYNC_STATUS_OK
) {
677 SyncCompleted(token
.Pass(), status
);
683 SyncCompleted(token
.Pass(), SYNC_STATUS_FAILED
);
687 metadata_database()->ReplaceActiveTrackerWithNewResource(
688 remote_parent_folder_tracker_
->tracker_id(), *entry
,
689 base::Bind(&LocalToRemoteSyncer::SyncCompleted
,
690 weak_ptr_factory_
.GetWeakPtr(),
691 base::Passed(&token
)));
694 void LocalToRemoteSyncer::CreateRemoteFolder(
695 scoped_ptr
<SyncTaskToken
> token
) {
696 DCHECK(remote_parent_folder_tracker_
);
698 base::FilePath title
= fileapi::VirtualPath::BaseName(target_path_
);
699 sync_action_
= SYNC_ACTION_ADDED
;
701 DCHECK(!folder_creator_
);
702 folder_creator_
.reset(new FolderCreator(
703 drive_service(), metadata_database(),
704 remote_parent_folder_tracker_
->file_id(),
705 title
.AsUTF8Unsafe()));
706 folder_creator_
->Run(base::Bind(
707 &LocalToRemoteSyncer::DidCreateRemoteFolder
,
708 weak_ptr_factory_
.GetWeakPtr(),
709 base::Passed(&token
)));
712 void LocalToRemoteSyncer::DidCreateRemoteFolder(
713 scoped_ptr
<SyncTaskToken
> token
,
714 const std::string
& file_id
,
715 SyncStatusCode status
) {
716 if (status
== SYNC_FILE_ERROR_NOT_FOUND
)
717 needs_remote_change_listing_
= true;
719 scoped_ptr
<FolderCreator
> deleter
= folder_creator_
.Pass();
720 if (status
!= SYNC_STATUS_OK
) {
721 SyncCompleted(token
.Pass(), status
);
725 MetadataDatabase::ActivationStatus activation_status
=
726 metadata_database()->TryActivateTracker(
727 remote_parent_folder_tracker_
->tracker_id(),
729 base::Bind(&LocalToRemoteSyncer::SyncCompleted
,
730 weak_ptr_factory_
.GetWeakPtr(),
731 base::Passed(token
.Pass())));
732 switch (activation_status
) {
733 case MetadataDatabase::ACTIVATION_PENDING
:
734 // The task will be finalized by the callback passed to MetadataDatabase
737 case MetadataDatabase::ACTIVATION_FAILED_ANOTHER_ACTIVE_TRACKER
:
738 // The activation failed due to another tracker that has another parent.
739 // Detach the folder from the current parent to avoid using this folder as
741 drive_service()->RemoveResourceFromDirectory(
742 remote_parent_folder_tracker_
->file_id(), file_id
,
743 base::Bind(&LocalToRemoteSyncer::DidDetachResourceForCreationConflict
,
744 weak_ptr_factory_
.GetWeakPtr(), base::Passed(&token
)));
749 SyncCompleted(token
.Pass(), SYNC_STATUS_FAILED
);
753 void LocalToRemoteSyncer::DidDetachResourceForCreationConflict(
754 scoped_ptr
<SyncTaskToken
> token
,
755 google_apis::GDataErrorCode error
) {
756 SyncStatusCode status
= GDataErrorCodeToSyncStatusCode(error
);
757 if (status
!= SYNC_STATUS_OK
) {
758 SyncCompleted(token
.Pass(), status
);
762 SyncCompleted(token
.Pass(), SYNC_STATUS_RETRY
);
765 bool LocalToRemoteSyncer::IsContextReady() {
766 return sync_context_
->GetDriveService() &&
767 sync_context_
->GetDriveUploader() &&
768 sync_context_
->GetMetadataDatabase();
771 drive::DriveServiceInterface
* LocalToRemoteSyncer::drive_service() {
772 set_used_network(true);
773 return sync_context_
->GetDriveService();
776 drive::DriveUploaderInterface
* LocalToRemoteSyncer::drive_uploader() {
777 set_used_network(true);
778 return sync_context_
->GetDriveUploader();
781 MetadataDatabase
* LocalToRemoteSyncer::metadata_database() {
782 return sync_context_
->GetMetadataDatabase();
785 } // namespace drive_backend
786 } // namespace sync_file_system