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/sync_file_system/drive_backend/callback_helper.h"
18 #include "chrome/browser/sync_file_system/drive_backend/drive_backend_constants.h"
19 #include "chrome/browser/sync_file_system/drive_backend/drive_backend_util.h"
20 #include "chrome/browser/sync_file_system/drive_backend/folder_creator.h"
21 #include "chrome/browser/sync_file_system/drive_backend/metadata_database.h"
22 #include "chrome/browser/sync_file_system/drive_backend/metadata_database.pb.h"
23 #include "chrome/browser/sync_file_system/drive_backend/sync_engine_context.h"
24 #include "chrome/browser/sync_file_system/drive_backend/sync_task_manager.h"
25 #include "chrome/browser/sync_file_system/drive_backend/sync_task_token.h"
26 #include "chrome/browser/sync_file_system/logger.h"
27 #include "components/drive/drive_api_util.h"
28 #include "components/drive/drive_uploader.h"
29 #include "components/drive/service/drive_service_interface.h"
30 #include "google_apis/drive/drive_api_parser.h"
31 #include "net/base/mime_util.h"
32 #include "storage/common/fileapi/file_system_util.h"
34 namespace sync_file_system
{
35 namespace drive_backend
{
39 scoped_ptr
<FileTracker
> FindTrackerByID(MetadataDatabase
* metadata_database
,
41 scoped_ptr
<FileTracker
> tracker(new FileTracker
);
42 if (metadata_database
->FindTrackerByTrackerID(tracker_id
, tracker
.get()))
43 return tracker
.Pass();
44 return scoped_ptr
<FileTracker
>();
47 bool GetKnownChangeID(MetadataDatabase
* metadata_database
,
48 const std::string
& file_id
,
50 FileMetadata remote_file_metadata
;
51 if (!metadata_database
->FindFileByFileID(file_id
, &remote_file_metadata
))
53 *change_id
= remote_file_metadata
.details().change_id();
57 bool IsLocalFileMissing(const SyncFileMetadata
& local_metadata
,
58 const FileChange
& local_change
) {
59 return local_metadata
.file_type
== SYNC_FILE_TYPE_UNKNOWN
||
60 local_change
.IsDelete();
63 std::string
GetMimeTypeFromTitle(const base::FilePath
& title
) {
64 base::FilePath::StringType extension
= title
.Extension();
65 std::string mime_type
;
66 if (extension
.empty() ||
67 !net::GetWellKnownMimeTypeFromExtension(extension
.substr(1), &mime_type
))
68 return kMimeTypeOctetStream
;
74 LocalToRemoteSyncer::LocalToRemoteSyncer(SyncEngineContext
* sync_context
,
75 const SyncFileMetadata
& local_metadata
,
76 const FileChange
& local_change
,
77 const base::FilePath
& local_path
,
78 const storage::FileSystemURL
& url
)
79 : sync_context_(sync_context
),
80 local_change_(local_change
),
81 local_is_missing_(IsLocalFileMissing(local_metadata
, local_change
)),
82 local_path_(local_path
),
84 file_type_(SYNC_FILE_TYPE_UNKNOWN
),
85 sync_action_(SYNC_ACTION_NONE
),
86 remote_file_change_id_(0),
87 retry_on_success_(false),
88 needs_remote_change_listing_(false),
89 weak_ptr_factory_(this) {
90 DCHECK(local_is_missing_
||
91 local_change
.file_type() == local_metadata
.file_type
)
92 << local_change
.DebugString() << " metadata:" << local_metadata
.file_type
;
95 LocalToRemoteSyncer::~LocalToRemoteSyncer() {
98 void LocalToRemoteSyncer::RunPreflight(scoped_ptr
<SyncTaskToken
> token
) {
99 token
->InitializeTaskLog("Local -> Remote");
101 if (!IsContextReady()) {
102 token
->RecordLog("Context not ready.");
103 SyncTaskManager::NotifyTaskDone(token
.Pass(), SYNC_STATUS_FAILED
);
107 token
->RecordLog(base::StringPrintf(
108 "Start: %s on %s@%s %s",
109 local_change_
.DebugString().c_str(),
110 url_
.path().AsUTF8Unsafe().c_str(),
111 url_
.origin().host().c_str(),
112 local_is_missing_
? "(missing)" : ""));
114 if (local_is_missing_
&& !local_change_
.IsDelete()) {
115 // Stray file, we can just return.
116 token
->RecordLog("Missing file for non-delete change.");
117 SyncTaskManager::NotifyTaskDone(token
.Pass(), SYNC_STATUS_OK
);
121 std::string app_id
= url_
.origin().host();
122 base::FilePath path
= url_
.path();
124 scoped_ptr
<FileTracker
> active_ancestor_tracker(new FileTracker
);
125 base::FilePath active_ancestor_path
;
126 if (!metadata_database()->FindNearestActiveAncestor(
128 active_ancestor_tracker
.get(), &active_ancestor_path
)) {
129 // The app is disabled or not registered.
130 token
->RecordLog("App is disabled or not registered");
131 SyncTaskManager::NotifyTaskDone(token
.Pass(), SYNC_STATUS_UNKNOWN_ORIGIN
);
134 DCHECK(active_ancestor_tracker
->active());
135 DCHECK(active_ancestor_tracker
->has_synced_details());
136 const FileDetails
& active_ancestor_details
=
137 active_ancestor_tracker
->synced_details();
139 // TODO(tzik): Consider handling
140 // active_ancestor_tracker->synced_details().missing() case.
142 DCHECK(active_ancestor_details
.file_kind() == FILE_KIND_FILE
||
143 active_ancestor_details
.file_kind() == FILE_KIND_FOLDER
);
145 base::FilePath missing_entries
;
146 if (active_ancestor_path
.empty()) {
147 missing_entries
= path
;
148 } else if (active_ancestor_path
!= path
) {
149 if (!active_ancestor_path
.AppendRelativePath(path
, &missing_entries
)) {
151 token
->RecordLog(base::StringPrintf(
152 "Detected invalid ancestor: %s",
153 active_ancestor_path
.value().c_str()));
154 SyncTaskManager::NotifyTaskDone(token
.Pass(), SYNC_STATUS_FAILED
);
159 std::vector
<base::FilePath::StringType
> missing_components
;
160 storage::VirtualPath::GetComponents(missing_entries
, &missing_components
);
162 if (!missing_components
.empty()) {
163 if (local_is_missing_
) {
164 token
->RecordLog("Both local and remote are marked missing");
165 // !IsDelete() but SYNC_FILE_TYPE_UNKNOWN could happen when a file is
166 // deleted by recursive deletion (which is not recorded by tracker)
167 // but there're remaining changes for the same file in the tracker.
169 // Local file is deleted and remote file is missing, already deleted or
170 // not yet synced. There is nothing to do for the file.
171 SyncTaskManager::NotifyTaskDone(token
.Pass(), SYNC_STATUS_OK
);
176 if (missing_components
.size() > 1) {
177 // The original target doesn't have remote file and parent.
178 // Try creating the parent first.
179 if (active_ancestor_details
.file_kind() == FILE_KIND_FOLDER
) {
180 remote_parent_folder_tracker_
= active_ancestor_tracker
.Pass();
181 target_path_
= active_ancestor_path
.Append(missing_components
[0]);
182 token
->RecordLog("Detected missing parent folder.");
184 retry_on_success_
= true;
185 MoveToBackground(base::Bind(&LocalToRemoteSyncer::CreateRemoteFolder
,
186 weak_ptr_factory_
.GetWeakPtr()),
191 DCHECK(active_ancestor_details
.file_kind() == FILE_KIND_FILE
);
192 remote_parent_folder_tracker_
=
193 FindTrackerByID(metadata_database(),
194 active_ancestor_tracker
->parent_tracker_id());
195 remote_file_tracker_
= active_ancestor_tracker
.Pass();
196 target_path_
= active_ancestor_path
;
197 token
->RecordLog("Detected non-folder file in its path.");
199 retry_on_success_
= true;
200 MoveToBackground(base::Bind(&LocalToRemoteSyncer::DeleteRemoteFile
,
201 weak_ptr_factory_
.GetWeakPtr()),
206 if (missing_components
.empty()) {
207 // The original target has remote active file/folder.
208 remote_parent_folder_tracker_
=
209 FindTrackerByID(metadata_database(),
210 active_ancestor_tracker
->parent_tracker_id());
211 remote_file_tracker_
= active_ancestor_tracker
.Pass();
212 target_path_
= url_
.path();
213 DCHECK(target_path_
== active_ancestor_path
);
215 if (remote_file_tracker_
->dirty()) {
216 token
->RecordLog(base::StringPrintf(
217 "Detected conflicting dirty tracker:%" PRId64
,
218 remote_file_tracker_
->tracker_id()));
219 // Both local and remote file has pending modification.
220 HandleConflict(token
.Pass());
224 // Non-conflicting file/folder update case.
225 HandleExistingRemoteFile(token
.Pass());
229 DCHECK(local_change_
.IsAddOrUpdate());
230 DCHECK_EQ(1u, missing_components
.size());
231 // The original target has remote parent folder and doesn't have remote active
233 // Upload the file as a new file or create a folder.
234 remote_parent_folder_tracker_
= active_ancestor_tracker
.Pass();
235 target_path_
= url_
.path();
236 DCHECK(target_path_
== active_ancestor_path
.Append(missing_components
[0]));
237 if (local_change_
.file_type() == SYNC_FILE_TYPE_FILE
) {
238 token
->RecordLog("Detected a new file.");
239 MoveToBackground(base::Bind(&LocalToRemoteSyncer::UploadNewFile
,
240 weak_ptr_factory_
.GetWeakPtr()),
245 token
->RecordLog("Detected a new folder.");
246 MoveToBackground(base::Bind(&LocalToRemoteSyncer::CreateRemoteFolder
,
247 weak_ptr_factory_
.GetWeakPtr()),
251 void LocalToRemoteSyncer::MoveToBackground(const Continuation
& continuation
,
252 scoped_ptr
<SyncTaskToken
> token
) {
253 scoped_ptr
<TaskBlocker
> blocker(new TaskBlocker
);
254 blocker
->app_id
= url_
.origin().host();
255 blocker
->paths
.push_back(target_path_
);
257 if (remote_file_tracker_
) {
258 if (!GetKnownChangeID(metadata_database(),
259 remote_file_tracker_
->file_id(),
260 &remote_file_change_id_
)) {
262 SyncCompleted(token
.Pass(), SYNC_STATUS_FAILED
);
266 blocker
->tracker_ids
.push_back(remote_file_tracker_
->tracker_id());
267 blocker
->file_ids
.push_back(remote_file_tracker_
->file_id());
270 // Run current task as a background task with |blocker|.
271 // After the invocation of ContinueAsBackgroundTask
272 SyncTaskManager::UpdateTaskBlocker(
273 token
.Pass(), blocker
.Pass(),
274 base::Bind(&LocalToRemoteSyncer::ContinueAsBackgroundTask
,
275 weak_ptr_factory_
.GetWeakPtr(),
279 void LocalToRemoteSyncer::ContinueAsBackgroundTask(
280 const Continuation
& continuation
,
281 scoped_ptr
<SyncTaskToken
> token
) {
282 // The SyncTask runs as a background task beyond this point.
283 // Note that any task can run between MoveToBackground() and
284 // ContinueAsBackgroundTask(), so we need to make sure other tasks didn't
285 // affect to the current LocalToRemoteSyncer task.
287 // - For RemoteToLocalSyncer, it doesn't actually run beyond
288 // PrepareForProcessRemoteChange() since it should be blocked in
289 // LocalFileSyncService.
290 // - For ListChangesTask, it may update FileMetatada together with |change_id|
291 // and may delete FileTracker. So, ensure |change_id| is not changed and
292 // check if FileTracker still exists.
293 // - For UninstallAppTask, it may also delete FileMetadata and FileTracker.
294 // Check if FileTracker still exists.
295 // - Others, SyncEngineInitializer and RegisterAppTask doesn't affect to
296 // LocalToRemoteSyncer.
297 if (remote_file_tracker_
) {
298 int64 latest_change_id
= 0;
299 if (!GetKnownChangeID(metadata_database(),
300 remote_file_tracker_
->file_id(),
301 &latest_change_id
) ||
302 latest_change_id
> remote_file_change_id_
) {
303 SyncCompleted(token
.Pass(), SYNC_STATUS_RETRY
);
307 if (!metadata_database()->FindTrackerByTrackerID(
308 remote_file_tracker_
->tracker_id(), nullptr)) {
309 SyncCompleted(token
.Pass(), SYNC_STATUS_RETRY
);
314 continuation
.Run(token
.Pass());
317 void LocalToRemoteSyncer::SyncCompleted(scoped_ptr
<SyncTaskToken
> token
,
318 SyncStatusCode status
) {
319 if (status
== SYNC_STATUS_OK
&& retry_on_success_
)
320 status
= SYNC_STATUS_RETRY
;
322 if (needs_remote_change_listing_
)
323 status
= SYNC_STATUS_FILE_BUSY
;
325 token
->RecordLog(base::StringPrintf(
326 "Finished: action=%s, status=%s for %s@%s",
327 SyncActionToString(sync_action_
),
328 SyncStatusCodeToString(status
),
329 target_path_
.AsUTF8Unsafe().c_str(),
330 url_
.origin().host().c_str()));
332 SyncTaskManager::NotifyTaskDone(token
.Pass(), status
);
335 void LocalToRemoteSyncer::HandleConflict(scoped_ptr
<SyncTaskToken
> token
) {
336 DCHECK(remote_file_tracker_
);
337 DCHECK(remote_file_tracker_
->has_synced_details());
338 DCHECK(remote_file_tracker_
->active());
339 DCHECK(remote_file_tracker_
->dirty());
341 if (local_is_missing_
) {
342 SyncCompleted(token
.Pass(), SYNC_STATUS_OK
);
346 if (local_change_
.IsFile()) {
347 // Upload the conflicting file as a new file and let ConflictResolver
349 MoveToBackground(base::Bind(&LocalToRemoteSyncer::UploadNewFile
,
350 weak_ptr_factory_
.GetWeakPtr()),
355 DCHECK(local_change_
.IsDirectory());
356 // Check if we can reuse the remote folder.
357 FileMetadata remote_file_metadata
;
358 if (!metadata_database()->FindFileByFileID(
359 remote_file_tracker_
->file_id(), &remote_file_metadata
)) {
361 MoveToBackground(base::Bind(&LocalToRemoteSyncer::CreateRemoteFolder
,
362 weak_ptr_factory_
.GetWeakPtr()),
367 const FileDetails
& remote_details
= remote_file_metadata
.details();
368 base::FilePath title
= storage::VirtualPath::BaseName(target_path_
);
369 if (!remote_details
.missing() &&
370 remote_details
.file_kind() == FILE_KIND_FOLDER
&&
371 remote_details
.title() == title
.AsUTF8Unsafe() &&
372 HasFileAsParent(remote_details
,
373 remote_parent_folder_tracker_
->file_id())) {
375 base::Bind(&LocalToRemoteSyncer::UpdateTrackerForReusedFolder
,
376 weak_ptr_factory_
.GetWeakPtr(),
382 MoveToBackground(base::Bind(&LocalToRemoteSyncer::CreateRemoteFolder
,
383 weak_ptr_factory_
.GetWeakPtr()),
387 void LocalToRemoteSyncer::UpdateTrackerForReusedFolder(
388 const FileDetails
& details
,
389 scoped_ptr
<SyncTaskToken
> token
) {
390 SyncStatusCode status
= metadata_database()->UpdateTracker(
391 remote_file_tracker_
->tracker_id(), details
);
392 SyncCompleted(token
.Pass(), status
);
395 void LocalToRemoteSyncer::HandleExistingRemoteFile(
396 scoped_ptr
<SyncTaskToken
> token
) {
397 DCHECK(remote_file_tracker_
);
398 DCHECK(!remote_file_tracker_
->dirty());
399 DCHECK(remote_file_tracker_
->active());
400 DCHECK(remote_file_tracker_
->has_synced_details());
402 if (local_is_missing_
) {
403 // Local file deletion for existing remote file.
404 MoveToBackground(base::Bind(&LocalToRemoteSyncer::DeleteRemoteFile
,
405 weak_ptr_factory_
.GetWeakPtr()),
410 DCHECK(local_change_
.IsAddOrUpdate());
411 DCHECK(local_change_
.IsFile() || local_change_
.IsDirectory());
413 const FileDetails
& synced_details
= remote_file_tracker_
->synced_details();
414 DCHECK(synced_details
.file_kind() == FILE_KIND_FILE
||
415 synced_details
.file_kind() == FILE_KIND_FOLDER
);
416 if (local_change_
.IsFile()) {
417 if (synced_details
.file_kind() == FILE_KIND_FILE
) {
418 // Non-conflicting local file update to existing remote regular file.
419 MoveToBackground(base::Bind(&LocalToRemoteSyncer::UploadExistingFile
,
420 weak_ptr_factory_
.GetWeakPtr()),
425 DCHECK_EQ(FILE_KIND_FOLDER
, synced_details
.file_kind());
426 // Non-conflicting local file update to existing remote *folder*.
427 // Assuming this case as local folder deletion + local file creation, delete
428 // the remote folder and upload the file.
429 retry_on_success_
= true;
430 MoveToBackground(base::Bind(&LocalToRemoteSyncer::DeleteRemoteFile
,
431 weak_ptr_factory_
.GetWeakPtr()),
436 DCHECK(local_change_
.IsDirectory());
437 if (synced_details
.file_kind() == FILE_KIND_FILE
) {
438 // Non-conflicting local folder creation to existing remote *file*.
439 // Assuming this case as local file deletion + local folder creation, delete
440 // the remote file and create a remote folder.
441 retry_on_success_
= true;
442 MoveToBackground(base::Bind(&LocalToRemoteSyncer::DeleteRemoteFile
,
443 weak_ptr_factory_
.GetWeakPtr()),
448 // Non-conflicting local folder creation to existing remote folder.
449 DCHECK_EQ(FILE_KIND_FOLDER
, synced_details
.file_kind());
450 SyncCompleted(token
.Pass(), SYNC_STATUS_OK
);
453 void LocalToRemoteSyncer::DeleteRemoteFile(scoped_ptr
<SyncTaskToken
> token
) {
454 DCHECK(remote_file_tracker_
);
455 DCHECK(remote_file_tracker_
->has_synced_details());
457 switch (remote_file_tracker_
->synced_details().file_kind()) {
458 case FILE_KIND_UNSUPPORTED
:
460 file_type_
= SYNC_FILE_TYPE_UNKNOWN
;
463 file_type_
= SYNC_FILE_TYPE_FILE
;
465 case FILE_KIND_FOLDER
:
466 file_type_
= SYNC_FILE_TYPE_DIRECTORY
;
469 sync_action_
= SYNC_ACTION_DELETED
;
470 drive_service()->DeleteResource(
471 remote_file_tracker_
->file_id(),
472 remote_file_tracker_
->synced_details().etag(),
473 base::Bind(&LocalToRemoteSyncer::DidDeleteRemoteFile
,
474 weak_ptr_factory_
.GetWeakPtr(), base::Passed(&token
)));
477 void LocalToRemoteSyncer::DidDeleteRemoteFile(
478 scoped_ptr
<SyncTaskToken
> token
,
479 google_apis::DriveApiErrorCode error
) {
480 SyncStatusCode status
= DriveApiErrorCodeToSyncStatusCode(error
);
481 if (status
!= SYNC_STATUS_OK
&&
482 error
!= google_apis::HTTP_NOT_FOUND
&&
483 error
!= google_apis::HTTP_PRECONDITION
&&
484 error
!= google_apis::HTTP_CONFLICT
) {
485 SyncCompleted(token
.Pass(), status
);
489 // Handle NOT_FOUND case as SUCCESS case.
490 // For PRECONDITION / CONFLICT case, the remote file is modified since the
491 // last sync completed. As our policy for deletion-modification conflict
492 // resolution, ignore the local deletion.
493 if (status
== SYNC_STATUS_OK
||
494 error
== google_apis::HTTP_NOT_FOUND
) {
495 SyncStatusCode status
= metadata_database()->UpdateByDeletedRemoteFile(
496 remote_file_tracker_
->file_id());
497 SyncCompleted(token
.Pass(), status
);
501 SyncCompleted(token
.Pass(), SYNC_STATUS_OK
);
504 void LocalToRemoteSyncer::UploadExistingFile(scoped_ptr
<SyncTaskToken
> token
) {
505 DCHECK(remote_file_tracker_
);
506 DCHECK(remote_file_tracker_
->has_synced_details());
507 DCHECK(sync_context_
->GetWorkerTaskRunner()->RunsTasksOnCurrentThread());
509 const std::string local_file_md5
= drive::util::GetMd5Digest(local_path_
,
511 if (local_file_md5
== remote_file_tracker_
->synced_details().md5()) {
512 // Local file is not changed.
513 SyncCompleted(token
.Pass(), SYNC_STATUS_OK
);
517 file_type_
= SYNC_FILE_TYPE_FILE
;
518 sync_action_
= SYNC_ACTION_UPDATED
;
520 drive::UploadExistingFileOptions options
;
521 options
.etag
= remote_file_tracker_
->synced_details().etag();
522 drive_uploader()->UploadExistingFile(
523 remote_file_tracker_
->file_id(),
525 "application/octet_stream",
527 base::Bind(&LocalToRemoteSyncer::DidUploadExistingFile
,
528 weak_ptr_factory_
.GetWeakPtr(), base::Passed(&token
)),
529 google_apis::ProgressCallback());
532 void LocalToRemoteSyncer::DidUploadExistingFile(
533 scoped_ptr
<SyncTaskToken
> token
,
534 google_apis::DriveApiErrorCode error
,
536 scoped_ptr
<google_apis::FileResource
> entry
) {
537 if (error
== google_apis::HTTP_PRECONDITION
||
538 error
== google_apis::HTTP_CONFLICT
||
539 error
== google_apis::HTTP_NOT_FOUND
) {
540 // The remote file has unfetched remote change. Fetch latest metadata and
541 // update database with it.
542 // TODO(tzik): Consider adding local side low-priority dirtiness handling to
543 // handle this as ListChangesTask.
545 needs_remote_change_listing_
= true;
546 UpdateRemoteMetadata(
547 remote_file_tracker_
->file_id(),
552 SyncStatusCode status
= DriveApiErrorCodeToSyncStatusCode(error
);
553 if (status
!= SYNC_STATUS_OK
) {
554 SyncCompleted(token
.Pass(), status
);
560 SyncCompleted(token
.Pass(), SYNC_STATUS_FAILED
);
565 status
= metadata_database()->UpdateByFileResource(*entry
);
566 if (status
!= SYNC_STATUS_OK
) {
567 SyncCompleted(token
.Pass(), status
);
572 if (!metadata_database()->FindFileByFileID(
573 remote_file_tracker_
->file_id(), &file
)) {
575 SyncCompleted(token
.Pass(), SYNC_STATUS_FAILED
);
579 const FileDetails
& details
= file
.details();
580 base::FilePath title
= storage::VirtualPath::BaseName(target_path_
);
581 if (!details
.missing() &&
582 details
.file_kind() == FILE_KIND_FILE
&&
583 details
.title() == title
.AsUTF8Unsafe() &&
584 HasFileAsParent(details
,
585 remote_parent_folder_tracker_
->file_id())) {
586 SyncStatusCode status
= metadata_database()->UpdateTracker(
587 remote_file_tracker_
->tracker_id(), file
.details());
588 SyncCompleted(token
.Pass(), status
);
592 SyncCompleted(token
.Pass(), SYNC_STATUS_RETRY
);
595 void LocalToRemoteSyncer::UpdateRemoteMetadata(
596 const std::string
& file_id
,
597 scoped_ptr
<SyncTaskToken
> token
) {
598 DCHECK(remote_file_tracker_
);
600 drive_service()->GetFileResource(
602 base::Bind(&LocalToRemoteSyncer::DidGetRemoteMetadata
,
603 weak_ptr_factory_
.GetWeakPtr(),
604 file_id
, base::Passed(&token
)));
607 void LocalToRemoteSyncer::DidGetRemoteMetadata(
608 const std::string
& file_id
,
609 scoped_ptr
<SyncTaskToken
> token
,
610 google_apis::DriveApiErrorCode error
,
611 scoped_ptr
<google_apis::FileResource
> entry
) {
612 DCHECK(sync_context_
->GetWorkerTaskRunner()->RunsTasksOnCurrentThread());
614 if (error
== google_apis::HTTP_NOT_FOUND
) {
615 retry_on_success_
= true;
616 SyncStatusCode status
=
617 metadata_database()->UpdateByDeletedRemoteFile(file_id
);
618 SyncCompleted(token
.Pass(), status
);
622 SyncStatusCode status
= DriveApiErrorCodeToSyncStatusCode(error
);
623 if (status
!= SYNC_STATUS_OK
) {
624 SyncCompleted(token
.Pass(), status
);
630 SyncCompleted(token
.Pass(), SYNC_STATUS_FAILED
);
634 retry_on_success_
= true;
635 status
= metadata_database()->UpdateByFileResource(*entry
);
636 SyncCompleted(token
.Pass(), status
);
639 void LocalToRemoteSyncer::UploadNewFile(scoped_ptr
<SyncTaskToken
> token
) {
640 DCHECK(remote_parent_folder_tracker_
);
642 file_type_
= SYNC_FILE_TYPE_FILE
;
643 sync_action_
= SYNC_ACTION_ADDED
;
644 base::FilePath title
= storage::VirtualPath::BaseName(target_path_
);
645 drive_uploader()->UploadNewFile(
646 remote_parent_folder_tracker_
->file_id(), local_path_
,
647 title
.AsUTF8Unsafe(), GetMimeTypeFromTitle(title
),
648 drive::UploadNewFileOptions(),
649 base::Bind(&LocalToRemoteSyncer::DidUploadNewFile
,
650 weak_ptr_factory_
.GetWeakPtr(), base::Passed(&token
)),
651 google_apis::ProgressCallback());
654 void LocalToRemoteSyncer::DidUploadNewFile(
655 scoped_ptr
<SyncTaskToken
> token
,
656 google_apis::DriveApiErrorCode error
,
657 const GURL
& upload_location
,
658 scoped_ptr
<google_apis::FileResource
> entry
) {
659 if (error
== google_apis::HTTP_NOT_FOUND
)
660 needs_remote_change_listing_
= true;
662 SyncStatusCode status
= DriveApiErrorCodeToSyncStatusCode(error
);
663 if (status
!= SYNC_STATUS_OK
) {
664 SyncCompleted(token
.Pass(), status
);
670 SyncCompleted(token
.Pass(), SYNC_STATUS_FAILED
);
674 status
= metadata_database()->ReplaceActiveTrackerWithNewResource(
675 remote_parent_folder_tracker_
->tracker_id(), *entry
);
676 SyncCompleted(token
.Pass(), status
);
679 void LocalToRemoteSyncer::CreateRemoteFolder(scoped_ptr
<SyncTaskToken
> token
) {
680 DCHECK(remote_parent_folder_tracker_
);
682 base::FilePath title
= storage::VirtualPath::BaseName(target_path_
);
683 file_type_
= SYNC_FILE_TYPE_DIRECTORY
;
684 sync_action_
= SYNC_ACTION_ADDED
;
686 DCHECK(!folder_creator_
);
687 folder_creator_
.reset(new FolderCreator(
688 drive_service(), metadata_database(),
689 remote_parent_folder_tracker_
->file_id(),
690 title
.AsUTF8Unsafe()));
691 folder_creator_
->Run(base::Bind(
692 &LocalToRemoteSyncer::DidCreateRemoteFolder
,
693 weak_ptr_factory_
.GetWeakPtr(),
694 base::Passed(&token
)));
697 void LocalToRemoteSyncer::DidCreateRemoteFolder(
698 scoped_ptr
<SyncTaskToken
> token
,
699 const std::string
& file_id
,
700 SyncStatusCode status
) {
701 if (status
== SYNC_FILE_ERROR_NOT_FOUND
)
702 needs_remote_change_listing_
= true;
704 scoped_ptr
<FolderCreator
> deleter
= folder_creator_
.Pass();
705 if (status
!= SYNC_STATUS_OK
) {
706 SyncCompleted(token
.Pass(), status
);
710 status
= SYNC_STATUS_FAILED
;
711 MetadataDatabase::ActivationStatus activation_status
=
712 metadata_database()->TryActivateTracker(
713 remote_parent_folder_tracker_
->tracker_id(),
715 switch (activation_status
) {
716 case MetadataDatabase::ACTIVATION_PENDING
:
717 SyncCompleted(token
.Pass(), status
);
719 case MetadataDatabase::ACTIVATION_FAILED_ANOTHER_ACTIVE_TRACKER
:
720 // The activation failed due to another tracker that has another parent.
721 // Detach the folder from the current parent to avoid using this folder as
723 drive_service()->RemoveResourceFromDirectory(
724 remote_parent_folder_tracker_
->file_id(), file_id
,
725 base::Bind(&LocalToRemoteSyncer::DidDetachResourceForCreationConflict
,
726 weak_ptr_factory_
.GetWeakPtr(), base::Passed(&token
)));
731 SyncCompleted(token
.Pass(), SYNC_STATUS_FAILED
);
735 void LocalToRemoteSyncer::DidDetachResourceForCreationConflict(
736 scoped_ptr
<SyncTaskToken
> token
,
737 google_apis::DriveApiErrorCode error
) {
738 SyncStatusCode status
= DriveApiErrorCodeToSyncStatusCode(error
);
739 if (status
!= SYNC_STATUS_OK
) {
740 SyncCompleted(token
.Pass(), status
);
744 SyncCompleted(token
.Pass(), SYNC_STATUS_RETRY
);
747 bool LocalToRemoteSyncer::IsContextReady() {
748 return sync_context_
->GetDriveService() &&
749 sync_context_
->GetDriveUploader() &&
750 sync_context_
->GetMetadataDatabase();
753 drive::DriveServiceInterface
* LocalToRemoteSyncer::drive_service() {
754 set_used_network(true);
755 return sync_context_
->GetDriveService();
758 drive::DriveUploaderInterface
* LocalToRemoteSyncer::drive_uploader() {
759 set_used_network(true);
760 return sync_context_
->GetDriveUploader();
763 MetadataDatabase
* LocalToRemoteSyncer::metadata_database() {
764 return sync_context_
->GetMetadataDatabase();
767 } // namespace drive_backend
768 } // namespace sync_file_system