Disable view source for Developer Tools.
[chromium-blink-merge.git] / chrome / browser / sync_file_system / drive_backend / local_to_remote_syncer.cc
blob1c0c280b020e09d70dba43046ae35cab9bf0faa6
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"
7 #include <string>
8 #include <vector>
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/task_runner_util.h"
16 #include "chrome/browser/drive/drive_api_util.h"
17 #include "chrome/browser/drive/drive_service_interface.h"
18 #include "chrome/browser/drive/drive_uploader.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/logger.h"
25 #include "google_apis/drive/drive_api_parser.h"
26 #include "webkit/common/fileapi/file_system_util.h"
28 namespace sync_file_system {
29 namespace drive_backend {
31 namespace {
33 scoped_ptr<FileTracker> FindTrackerByID(MetadataDatabase* metadata_database,
34 int64 tracker_id) {
35 scoped_ptr<FileTracker> tracker(new FileTracker);
36 if (metadata_database->FindTrackerByTrackerID(tracker_id, tracker.get()))
37 return tracker.Pass();
38 return scoped_ptr<FileTracker>();
41 void ReturnRetryOnSuccess(const SyncStatusCallback& callback,
42 SyncStatusCode status) {
43 if (status == SYNC_STATUS_OK)
44 status = SYNC_STATUS_RETRY;
45 callback.Run(status);
48 bool IsLocalFileMissing(const SyncFileMetadata& local_metadata,
49 const FileChange& local_change) {
50 return local_metadata.file_type == SYNC_FILE_TYPE_UNKNOWN ||
51 local_change.IsDelete();
54 } // namespace
56 LocalToRemoteSyncer::LocalToRemoteSyncer(SyncEngineContext* sync_context,
57 const SyncFileMetadata& local_metadata,
58 const FileChange& local_change,
59 const base::FilePath& local_path,
60 const fileapi::FileSystemURL& url)
61 : sync_context_(sync_context),
62 local_change_(local_change),
63 local_is_missing_(IsLocalFileMissing(local_metadata, local_change)),
64 local_path_(local_path),
65 url_(url),
66 sync_action_(SYNC_ACTION_NONE),
67 needs_remote_change_listing_(false),
68 weak_ptr_factory_(this) {
69 DCHECK(local_is_missing_ ||
70 local_change.file_type() == local_metadata.file_type)
71 << local_change.DebugString() << " metadata:" << local_metadata.file_type;
74 LocalToRemoteSyncer::~LocalToRemoteSyncer() {
77 void LocalToRemoteSyncer::Run(const SyncStatusCallback& callback) {
78 if (!IsContextReady()) {
79 util::Log(logging::LOG_VERBOSE, FROM_HERE,
80 "[Local -> Remote] Context not ready.");
81 NOTREACHED();
82 callback.Run(SYNC_STATUS_FAILED);
83 return;
86 SyncStatusCallback wrapped_callback = base::Bind(
87 &LocalToRemoteSyncer::SyncCompleted, weak_ptr_factory_.GetWeakPtr(),
88 callback);
90 util::Log(logging::LOG_VERBOSE, FROM_HERE,
91 "[Local -> Remote] Start: %s on %s@%s %s",
92 local_change_.DebugString().c_str(),
93 url_.path().AsUTF8Unsafe().c_str(),
94 url_.origin().host().c_str(),
95 local_is_missing_ ? "(missing)" : "");
97 if (local_is_missing_ && !local_change_.IsDelete()) {
98 // Stray file, we can just return.
99 util::Log(logging::LOG_VERBOSE, FROM_HERE,
100 "[Local -> Remote]: Missing file for non-delete change");
101 callback.Run(SYNC_STATUS_OK);
102 return;
105 std::string app_id = url_.origin().host();
106 base::FilePath path = url_.path();
108 scoped_ptr<FileTracker> active_ancestor_tracker(new FileTracker);
109 base::FilePath active_ancestor_path;
110 if (!metadata_database()->FindNearestActiveAncestor(
111 app_id, path,
112 active_ancestor_tracker.get(), &active_ancestor_path)) {
113 // The app is disabled or not registered.
114 util::Log(logging::LOG_VERBOSE, FROM_HERE,
115 "[Local -> Remote]: App is disabled or not registered");
116 callback.Run(SYNC_STATUS_UNKNOWN_ORIGIN);
117 return;
119 DCHECK(active_ancestor_tracker->active());
120 DCHECK(active_ancestor_tracker->has_synced_details());
121 const FileDetails& active_ancestor_details =
122 active_ancestor_tracker->synced_details();
124 // TODO(tzik): Consider handling
125 // active_ancestor_tracker->synced_details().missing() case.
127 DCHECK(active_ancestor_details.file_kind() == FILE_KIND_FILE ||
128 active_ancestor_details.file_kind() == FILE_KIND_FOLDER);
130 base::FilePath missing_entries;
131 if (active_ancestor_path.empty()) {
132 missing_entries = path;
133 } else if (active_ancestor_path != path) {
134 bool should_success = active_ancestor_path.AppendRelativePath(
135 path, &missing_entries);
136 if (!should_success) {
137 NOTREACHED() << "[Local -> Remote]: Detected invalid ancestor: "
138 << active_ancestor_path.value();
139 callback.Run(SYNC_STATUS_FAILED);
140 return;
144 std::vector<base::FilePath::StringType> missing_components;
145 fileapi::VirtualPath::GetComponents(missing_entries, &missing_components);
147 if (!missing_components.empty()) {
148 if (local_is_missing_) {
149 util::Log(logging::LOG_VERBOSE, FROM_HERE,
150 "[Local -> Remote]: Both local and remote are marked missing");
151 // !IsDelete() but SYNC_FILE_TYPE_UNKNOWN could happen when a file is
152 // deleted by recursive deletion (which is not recorded by tracker)
153 // but there're remaining changes for the same file in the tracker.
155 // Local file is deleted and remote file is missing, already deleted or
156 // not yet synced. There is nothing to do for the file.
157 callback.Run(SYNC_STATUS_OK);
158 return;
162 if (missing_components.size() > 1) {
163 // The original target doesn't have remote file and parent.
164 // Try creating the parent first.
165 if (active_ancestor_details.file_kind() == FILE_KIND_FOLDER) {
166 remote_parent_folder_tracker_ = active_ancestor_tracker.Pass();
167 target_path_ = active_ancestor_path.Append(missing_components[0]);
168 util::Log(logging::LOG_VERBOSE, FROM_HERE,
169 "[Local -> Remote]: Detected missing parent folder.");
170 CreateRemoteFolder(wrapped_callback);
171 return;
174 DCHECK(active_ancestor_details.file_kind() == FILE_KIND_FILE);
175 remote_parent_folder_tracker_ =
176 FindTrackerByID(metadata_database(),
177 active_ancestor_tracker->parent_tracker_id());
178 remote_file_tracker_ = active_ancestor_tracker.Pass();
179 target_path_ = active_ancestor_path;
180 util::Log(logging::LOG_VERBOSE, FROM_HERE,
181 "[Local -> Remote]: Detected non-folder file in its path.");
182 DeleteRemoteFile(base::Bind(&LocalToRemoteSyncer::DidDeleteForCreateFolder,
183 weak_ptr_factory_.GetWeakPtr(),
184 wrapped_callback));
186 return;
189 if (missing_components.empty()) {
190 // The original target has remote active file/folder.
191 remote_parent_folder_tracker_ =
192 FindTrackerByID(metadata_database(),
193 active_ancestor_tracker->parent_tracker_id());
194 remote_file_tracker_ = active_ancestor_tracker.Pass();
195 target_path_ = url_.path();
196 DCHECK(target_path_ == active_ancestor_path);
198 if (remote_file_tracker_->dirty()) {
199 util::Log(logging::LOG_VERBOSE, FROM_HERE,
200 "[Local -> Remote]: Detected conflicting dirty tracker:%"
201 PRId64, remote_file_tracker_->tracker_id());
202 // Both local and remote file has pending modification.
203 HandleConflict(wrapped_callback);
204 return;
207 // Non-conflicting file/folder update case.
208 HandleExistingRemoteFile(wrapped_callback);
209 return;
212 DCHECK(local_change_.IsAddOrUpdate());
213 DCHECK_EQ(1u, missing_components.size());
214 // The original target has remote parent folder and doesn't have remote active
215 // file.
216 // Upload the file as a new file or create a folder.
217 remote_parent_folder_tracker_ = active_ancestor_tracker.Pass();
218 target_path_ = url_.path();
219 DCHECK(target_path_ == active_ancestor_path.Append(missing_components[0]));
220 if (local_change_.file_type() == SYNC_FILE_TYPE_FILE) {
221 util::Log(logging::LOG_VERBOSE, FROM_HERE,
222 "[Local -> Remote]: Detected a new file.");
223 UploadNewFile(wrapped_callback);
224 return;
226 util::Log(logging::LOG_VERBOSE, FROM_HERE,
227 "[Local -> Remote]: Detected a new folder.");
228 CreateRemoteFolder(wrapped_callback);
231 void LocalToRemoteSyncer::SyncCompleted(const SyncStatusCallback& callback,
232 SyncStatusCode status) {
233 if (status == SYNC_STATUS_OK && target_path_ != url_.path())
234 status = SYNC_STATUS_RETRY;
236 if (needs_remote_change_listing_)
237 status = SYNC_STATUS_FILE_BUSY;
239 util::Log(logging::LOG_VERBOSE, FROM_HERE,
240 "[Local -> Remote]: Finished: action=%s, status=%s for %s@%s",
241 SyncActionToString(sync_action_),
242 SyncStatusCodeToString(status),
243 target_path_.AsUTF8Unsafe().c_str(),
244 url_.origin().host().c_str());
246 callback.Run(status);
249 void LocalToRemoteSyncer::HandleConflict(const SyncStatusCallback& callback) {
250 DCHECK(remote_file_tracker_);
251 DCHECK(remote_file_tracker_->has_synced_details());
252 DCHECK(remote_file_tracker_->active());
253 DCHECK(remote_file_tracker_->dirty());
255 if (local_is_missing_) {
256 callback.Run(SYNC_STATUS_OK);
257 return;
260 if (local_change_.IsFile()) {
261 UploadNewFile(callback);
262 return;
265 DCHECK(local_change_.IsDirectory());
266 // Check if we can reuse the remote folder.
267 FileMetadata remote_file_metadata;
268 bool should_success = metadata_database()->FindFileByFileID(
269 remote_file_tracker_->file_id(), &remote_file_metadata);
270 if (!should_success) {
271 NOTREACHED();
272 CreateRemoteFolder(callback);
273 return;
276 const FileDetails& remote_details = remote_file_metadata.details();
277 base::FilePath title = fileapi::VirtualPath::BaseName(target_path_);
278 if (!remote_details.missing() &&
279 remote_details.file_kind() == FILE_KIND_FOLDER &&
280 remote_details.title() == title.AsUTF8Unsafe() &&
281 HasFileAsParent(remote_details,
282 remote_parent_folder_tracker_->file_id())) {
283 metadata_database()->UpdateTracker(
284 remote_file_tracker_->tracker_id(), remote_details, callback);
285 return;
288 // Create new remote folder.
289 CreateRemoteFolder(callback);
292 void LocalToRemoteSyncer::HandleExistingRemoteFile(
293 const SyncStatusCallback& callback) {
294 DCHECK(remote_file_tracker_);
295 DCHECK(!remote_file_tracker_->dirty());
296 DCHECK(remote_file_tracker_->active());
297 DCHECK(remote_file_tracker_->has_synced_details());
299 if (local_is_missing_) {
300 // Local file deletion for existing remote file.
301 DeleteRemoteFile(callback);
302 return;
305 DCHECK(local_change_.IsAddOrUpdate());
306 DCHECK(local_change_.IsFile() || local_change_.IsDirectory());
308 const FileDetails& synced_details = remote_file_tracker_->synced_details();
309 DCHECK(synced_details.file_kind() == FILE_KIND_FILE ||
310 synced_details.file_kind() == FILE_KIND_FOLDER);
311 if (local_change_.IsFile()) {
312 if (synced_details.file_kind() == FILE_KIND_FILE) {
313 // Non-conflicting local file update to existing remote regular file.
314 UploadExistingFile(callback);
315 return;
318 DCHECK_EQ(FILE_KIND_FOLDER, synced_details.file_kind());
319 // Non-conflicting local file update to existing remote *folder*.
320 // Assuming this case as local folder deletion + local file creation, delete
321 // the remote folder and upload the file.
322 DeleteRemoteFile(base::Bind(&LocalToRemoteSyncer::DidDeleteForUploadNewFile,
323 weak_ptr_factory_.GetWeakPtr(),
324 callback));
325 return;
328 DCHECK(local_change_.IsDirectory());
329 if (synced_details.file_kind() == FILE_KIND_FILE) {
330 // Non-conflicting local folder creation to existing remote *file*.
331 // Assuming this case as local file deletion + local folder creation, delete
332 // the remote file and create a remote folder.
333 DeleteRemoteFile(base::Bind(&LocalToRemoteSyncer::DidDeleteForCreateFolder,
334 weak_ptr_factory_.GetWeakPtr(), callback));
335 return;
338 // Non-conflicting local folder creation to existing remote folder.
339 DCHECK_EQ(FILE_KIND_FOLDER, synced_details.file_kind());
340 callback.Run(SYNC_STATUS_OK);
343 void LocalToRemoteSyncer::DeleteRemoteFile(
344 const SyncStatusCallback& callback) {
345 DCHECK(remote_file_tracker_);
346 DCHECK(remote_file_tracker_->has_synced_details());
348 sync_action_ = SYNC_ACTION_DELETED;
349 drive_service()->DeleteResource(
350 remote_file_tracker_->file_id(),
351 remote_file_tracker_->synced_details().etag(),
352 base::Bind(&LocalToRemoteSyncer::DidDeleteRemoteFile,
353 weak_ptr_factory_.GetWeakPtr(),
354 callback));
357 void LocalToRemoteSyncer::DidDeleteRemoteFile(
358 const SyncStatusCallback& callback,
359 google_apis::GDataErrorCode error) {
360 SyncStatusCode status = GDataErrorCodeToSyncStatusCode(error);
361 if (status != SYNC_STATUS_OK &&
362 error != google_apis::HTTP_NOT_FOUND &&
363 error != google_apis::HTTP_PRECONDITION &&
364 error != google_apis::HTTP_CONFLICT) {
365 callback.Run(status);
366 return;
369 // Handle NOT_FOUND case as SUCCESS case.
370 // For PRECONDITION / CONFLICT case, the remote file is modified since the
371 // last sync completed. As our policy for deletion-modification conflict
372 // resolution, ignore the local deletion.
373 callback.Run(SYNC_STATUS_OK);
376 void LocalToRemoteSyncer::UploadExistingFile(
377 const SyncStatusCallback& callback) {
378 DCHECK(remote_file_tracker_);
379 DCHECK(remote_file_tracker_->has_synced_details());
381 base::PostTaskAndReplyWithResult(
382 sync_context_->GetBlockingTaskRunner(), FROM_HERE,
383 base::Bind(&drive::util::GetMd5Digest, local_path_),
384 base::Bind(&LocalToRemoteSyncer::DidGetMD5ForUpload,
385 weak_ptr_factory_.GetWeakPtr(),
386 callback));
389 void LocalToRemoteSyncer::DidGetMD5ForUpload(
390 const SyncStatusCallback& callback,
391 const std::string& local_file_md5) {
392 if (local_file_md5 == remote_file_tracker_->synced_details().md5()) {
393 // Local file is not changed.
394 callback.Run(SYNC_STATUS_OK);
395 return;
398 sync_action_ = SYNC_ACTION_UPDATED;
399 drive_uploader()->UploadExistingFile(
400 remote_file_tracker_->file_id(),
401 local_path_,
402 "application/octet_stream",
403 remote_file_tracker_->synced_details().etag(),
404 base::Bind(&LocalToRemoteSyncer::DidUploadExistingFile,
405 weak_ptr_factory_.GetWeakPtr(),
406 callback),
407 google_apis::ProgressCallback());
410 void LocalToRemoteSyncer::DidUploadExistingFile(
411 const SyncStatusCallback& callback,
412 google_apis::GDataErrorCode error,
413 const GURL&,
414 scoped_ptr<google_apis::ResourceEntry> entry) {
415 if (error == google_apis::HTTP_PRECONDITION ||
416 error == google_apis::HTTP_CONFLICT ||
417 error == google_apis::HTTP_NOT_FOUND) {
418 // The remote file has unfetched remote change. Fetch latest metadata and
419 // update database with it.
420 // TODO(tzik): Consider adding local side low-priority dirtiness handling to
421 // handle this as ListChangesTask.
423 needs_remote_change_listing_ = true;
424 UpdateRemoteMetadata(remote_file_tracker_->file_id(),
425 base::Bind(&ReturnRetryOnSuccess, callback));
426 return;
429 SyncStatusCode status = GDataErrorCodeToSyncStatusCode(error);
430 if (status != SYNC_STATUS_OK) {
431 callback.Run(status);
432 return;
435 if (!entry) {
436 NOTREACHED();
437 callback.Run(SYNC_STATUS_FAILED);
438 return;
441 DCHECK(entry);
442 metadata_database()->UpdateByFileResource(
443 *drive::util::ConvertResourceEntryToFileResource(*entry),
444 base::Bind(&LocalToRemoteSyncer::DidUpdateDatabaseForUploadExistingFile,
445 weak_ptr_factory_.GetWeakPtr(),
446 callback));
449 void LocalToRemoteSyncer::DidUpdateDatabaseForUploadExistingFile(
450 const SyncStatusCallback& callback,
451 SyncStatusCode status) {
452 if (status != SYNC_STATUS_OK) {
453 callback.Run(status);
454 return;
457 FileMetadata file;
458 bool should_success = metadata_database()->FindFileByFileID(
459 remote_file_tracker_->file_id(), &file);
460 if (!should_success) {
461 NOTREACHED();
462 callback.Run(SYNC_STATUS_FAILED);
463 return;
466 const FileDetails& details = file.details();
467 base::FilePath title = fileapi::VirtualPath::BaseName(target_path_);
468 if (!details.missing() &&
469 details.file_kind() == FILE_KIND_FILE &&
470 details.title() == title.AsUTF8Unsafe() &&
471 HasFileAsParent(details,
472 remote_parent_folder_tracker_->file_id())) {
473 metadata_database()->UpdateTracker(
474 remote_file_tracker_->tracker_id(),
475 file.details(),
476 callback);
477 return;
480 callback.Run(SYNC_STATUS_RETRY);
483 void LocalToRemoteSyncer::UpdateRemoteMetadata(
484 const std::string& file_id,
485 const SyncStatusCallback& callback) {
486 DCHECK(remote_file_tracker_);
487 drive_service()->GetResourceEntry(
488 file_id,
489 base::Bind(&LocalToRemoteSyncer::DidGetRemoteMetadata,
490 weak_ptr_factory_.GetWeakPtr(),
491 file_id, callback));
494 void LocalToRemoteSyncer::DidGetRemoteMetadata(
495 const std::string& file_id,
496 const SyncStatusCallback& callback,
497 google_apis::GDataErrorCode error,
498 scoped_ptr<google_apis::ResourceEntry> entry) {
499 if (error == google_apis::HTTP_NOT_FOUND) {
500 metadata_database()->UpdateByDeletedRemoteFile(file_id, callback);
501 return;
504 SyncStatusCode status = GDataErrorCodeToSyncStatusCode(error);
505 if (status != SYNC_STATUS_OK) {
506 callback.Run(status);
507 return;
510 if (!entry) {
511 NOTREACHED();
512 callback.Run(SYNC_STATUS_FAILED);
513 return;
516 metadata_database()->UpdateByFileResource(
517 *drive::util::ConvertResourceEntryToFileResource(*entry), callback);
520 void LocalToRemoteSyncer::DidDeleteForUploadNewFile(
521 const SyncStatusCallback& callback,
522 SyncStatusCode status) {
523 if (status == SYNC_STATUS_HAS_CONFLICT) {
524 UpdateRemoteMetadata(remote_file_tracker_->file_id(),
525 base::Bind(&ReturnRetryOnSuccess, callback));
526 return;
529 if (status != SYNC_STATUS_OK) {
530 callback.Run(status);
531 return;
534 UploadNewFile(callback);
537 void LocalToRemoteSyncer::DidDeleteForCreateFolder(
538 const SyncStatusCallback& callback,
539 SyncStatusCode status) {
540 if (status == SYNC_STATUS_HAS_CONFLICT) {
541 UpdateRemoteMetadata(remote_file_tracker_->file_id(),
542 base::Bind(&ReturnRetryOnSuccess, callback));
543 return;
546 if (status != SYNC_STATUS_OK) {
547 callback.Run(status);
548 return;
551 CreateRemoteFolder(callback);
554 void LocalToRemoteSyncer::UploadNewFile(const SyncStatusCallback& callback) {
555 DCHECK(remote_parent_folder_tracker_);
557 sync_action_ = SYNC_ACTION_ADDED;
558 base::FilePath title = fileapi::VirtualPath::BaseName(target_path_);
559 drive_uploader()->UploadNewFile(
560 remote_parent_folder_tracker_->file_id(),
561 local_path_,
562 title.AsUTF8Unsafe(),
563 GetMimeTypeFromTitle(title),
564 base::Bind(&LocalToRemoteSyncer::DidUploadNewFile,
565 weak_ptr_factory_.GetWeakPtr(),
566 callback),
567 google_apis::ProgressCallback());
570 void LocalToRemoteSyncer::DidUploadNewFile(
571 const SyncStatusCallback& callback,
572 google_apis::GDataErrorCode error,
573 const GURL& upload_location,
574 scoped_ptr<google_apis::ResourceEntry> entry) {
575 if (error == google_apis::HTTP_NOT_FOUND)
576 needs_remote_change_listing_ = true;
578 SyncStatusCode status = GDataErrorCodeToSyncStatusCode(error);
579 if (status != SYNC_STATUS_OK) {
580 callback.Run(status);
581 return;
584 if (!entry) {
585 NOTREACHED();
586 callback.Run(SYNC_STATUS_FAILED);
587 return;
590 metadata_database()->ReplaceActiveTrackerWithNewResource(
591 remote_parent_folder_tracker_->tracker_id(),
592 *drive::util::ConvertResourceEntryToFileResource(*entry),
593 callback);
596 void LocalToRemoteSyncer::CreateRemoteFolder(
597 const SyncStatusCallback& callback) {
598 DCHECK(remote_parent_folder_tracker_);
600 base::FilePath title = fileapi::VirtualPath::BaseName(target_path_);
601 sync_action_ = SYNC_ACTION_ADDED;
603 DCHECK(!folder_creator_);
604 folder_creator_.reset(new FolderCreator(
605 drive_service(), metadata_database(),
606 remote_parent_folder_tracker_->file_id(),
607 title.AsUTF8Unsafe()));
608 folder_creator_->Run(base::Bind(
609 &LocalToRemoteSyncer::DidCreateRemoteFolder,
610 weak_ptr_factory_.GetWeakPtr(),
611 callback));
614 void LocalToRemoteSyncer::DidCreateRemoteFolder(
615 const SyncStatusCallback& callback,
616 const std::string& file_id,
617 SyncStatusCode status) {
618 if (status == SYNC_FILE_ERROR_NOT_FOUND)
619 needs_remote_change_listing_ = true;
621 scoped_ptr<FolderCreator> deleter = folder_creator_.Pass();
622 if (status != SYNC_STATUS_OK) {
623 callback.Run(status);
624 return;
627 if (metadata_database()->TryNoSideEffectActivation(
628 remote_parent_folder_tracker_->tracker_id(),
629 file_id, callback)) {
630 // |callback| will be invoked by MetadataDatabase in this case.
631 return;
634 drive_service()->RemoveResourceFromDirectory(
635 remote_parent_folder_tracker_->file_id(), file_id,
636 base::Bind(&LocalToRemoteSyncer::DidDetachResourceForCreationConflict,
637 weak_ptr_factory_.GetWeakPtr(),
638 callback));
641 void LocalToRemoteSyncer::DidDetachResourceForCreationConflict(
642 const SyncStatusCallback& callback,
643 google_apis::GDataErrorCode error) {
644 SyncStatusCode status = GDataErrorCodeToSyncStatusCode(error);
645 if (status != SYNC_STATUS_OK) {
646 callback.Run(status);
647 return;
650 callback.Run(SYNC_STATUS_RETRY);
653 bool LocalToRemoteSyncer::IsContextReady() {
654 return sync_context_->GetDriveService() &&
655 sync_context_->GetDriveUploader() &&
656 sync_context_->GetMetadataDatabase();
659 drive::DriveServiceInterface* LocalToRemoteSyncer::drive_service() {
660 set_used_network(true);
661 return sync_context_->GetDriveService();
664 drive::DriveUploaderInterface* LocalToRemoteSyncer::drive_uploader() {
665 set_used_network(true);
666 return sync_context_->GetDriveUploader();
669 MetadataDatabase* LocalToRemoteSyncer::metadata_database() {
670 return sync_context_->GetMetadataDatabase();
673 } // namespace drive_backend
674 } // namespace sync_file_system