local_to_remote_syncer.cc revision e5d81f57cb97b3b6b7fccc9c5610d21eb81db09d
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. 4 5#include "chrome/browser/sync_file_system/drive_backend/local_to_remote_syncer.h" 6 7#include <string> 8#include <vector> 9 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" 27 28namespace sync_file_system { 29namespace drive_backend { 30 31namespace { 32 33scoped_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>(); 39} 40 41void ReturnRetryOnSuccess(const SyncStatusCallback& callback, 42 SyncStatusCode status) { 43 if (status == SYNC_STATUS_OK) 44 status = SYNC_STATUS_RETRY; 45 callback.Run(status); 46} 47 48bool IsLocalFileMissing(const SyncFileMetadata& local_metadata, 49 const FileChange& local_change) { 50 return local_metadata.file_type == SYNC_FILE_TYPE_UNKNOWN || 51 local_change.IsDelete(); 52} 53 54} // namespace 55 56LocalToRemoteSyncer::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; 72} 73 74LocalToRemoteSyncer::~LocalToRemoteSyncer() { 75} 76 77void LocalToRemoteSyncer::RunExclusive(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; 84 } 85 86 SyncStatusCallback wrapped_callback = base::Bind( 87 &LocalToRemoteSyncer::SyncCompleted, weak_ptr_factory_.GetWeakPtr(), 88 callback); 89 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)" : ""); 96 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; 103 } 104 105 std::string app_id = url_.origin().host(); 106 base::FilePath path = url_.path(); 107 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; 118 } 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(); 123 124 // TODO(tzik): Consider handling 125 // active_ancestor_tracker->synced_details().missing() case. 126 127 DCHECK(active_ancestor_details.file_kind() == FILE_KIND_FILE || 128 active_ancestor_details.file_kind() == FILE_KIND_FOLDER); 129 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; 141 } 142 } 143 144 std::vector<base::FilePath::StringType> missing_components; 145 fileapi::VirtualPath::GetComponents(missing_entries, &missing_components); 146 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. 154 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; 159 } 160 } 161 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; 172 } 173 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)); 185 186 return; 187 } 188 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); 197 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; 205 } 206 207 // Non-conflicting file/folder update case. 208 HandleExistingRemoteFile(wrapped_callback); 209 return; 210 } 211 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; 225 } 226 util::Log(logging::LOG_VERBOSE, FROM_HERE, 227 "[Local -> Remote]: Detected a new folder."); 228 CreateRemoteFolder(wrapped_callback); 229} 230 231void LocalToRemoteSyncer::SyncCompleted(const SyncStatusCallback& callback, 232 SyncStatusCode status) { 233 if (status == SYNC_STATUS_OK && target_path_ != url_.path()) 234 status = SYNC_STATUS_RETRY; 235 236 if (needs_remote_change_listing_) 237 status = SYNC_STATUS_FILE_BUSY; 238 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()); 245 246 callback.Run(status); 247} 248 249void 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()); 254 255 if (local_is_missing_) { 256 callback.Run(SYNC_STATUS_OK); 257 return; 258 } 259 260 if (local_change_.IsFile()) { 261 UploadNewFile(callback); 262 return; 263 } 264 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; 274 } 275 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; 286 } 287 288 // Create new remote folder. 289 CreateRemoteFolder(callback); 290} 291 292void 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()); 298 299 if (local_is_missing_) { 300 // Local file deletion for existing remote file. 301 DeleteRemoteFile(callback); 302 return; 303 } 304 305 DCHECK(local_change_.IsAddOrUpdate()); 306 DCHECK(local_change_.IsFile() || local_change_.IsDirectory()); 307 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; 316 } 317 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; 326 } 327 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; 336 } 337 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); 341} 342 343void LocalToRemoteSyncer::DeleteRemoteFile( 344 const SyncStatusCallback& callback) { 345 DCHECK(remote_file_tracker_); 346 DCHECK(remote_file_tracker_->has_synced_details()); 347 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)); 355} 356 357void 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; 367 } 368 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 if (error == google_apis::HTTP_NOT_FOUND) { 374 metadata_database()->UpdateByDeletedRemoteFile( 375 remote_file_tracker_->file_id(), callback); 376 return; 377 } 378 callback.Run(SYNC_STATUS_OK); 379} 380 381void LocalToRemoteSyncer::UploadExistingFile( 382 const SyncStatusCallback& callback) { 383 DCHECK(remote_file_tracker_); 384 DCHECK(remote_file_tracker_->has_synced_details()); 385 386 base::PostTaskAndReplyWithResult( 387 sync_context_->GetBlockingTaskRunner(), FROM_HERE, 388 base::Bind(&drive::util::GetMd5Digest, local_path_), 389 base::Bind(&LocalToRemoteSyncer::DidGetMD5ForUpload, 390 weak_ptr_factory_.GetWeakPtr(), 391 callback)); 392} 393 394void LocalToRemoteSyncer::DidGetMD5ForUpload( 395 const SyncStatusCallback& callback, 396 const std::string& local_file_md5) { 397 if (local_file_md5 == remote_file_tracker_->synced_details().md5()) { 398 // Local file is not changed. 399 callback.Run(SYNC_STATUS_OK); 400 return; 401 } 402 403 sync_action_ = SYNC_ACTION_UPDATED; 404 405 drive::DriveUploader::UploadExistingFileOptions options; 406 options.etag = remote_file_tracker_->synced_details().etag(); 407 drive_uploader()->UploadExistingFile( 408 remote_file_tracker_->file_id(), 409 local_path_, 410 "application/octet_stream", 411 options, 412 base::Bind(&LocalToRemoteSyncer::DidUploadExistingFile, 413 weak_ptr_factory_.GetWeakPtr(), 414 callback), 415 google_apis::ProgressCallback()); 416} 417 418void LocalToRemoteSyncer::DidUploadExistingFile( 419 const SyncStatusCallback& callback, 420 google_apis::GDataErrorCode error, 421 const GURL&, 422 scoped_ptr<google_apis::ResourceEntry> entry) { 423 if (error == google_apis::HTTP_PRECONDITION || 424 error == google_apis::HTTP_CONFLICT || 425 error == google_apis::HTTP_NOT_FOUND) { 426 // The remote file has unfetched remote change. Fetch latest metadata and 427 // update database with it. 428 // TODO(tzik): Consider adding local side low-priority dirtiness handling to 429 // handle this as ListChangesTask. 430 431 needs_remote_change_listing_ = true; 432 UpdateRemoteMetadata(remote_file_tracker_->file_id(), 433 base::Bind(&ReturnRetryOnSuccess, callback)); 434 return; 435 } 436 437 SyncStatusCode status = GDataErrorCodeToSyncStatusCode(error); 438 if (status != SYNC_STATUS_OK) { 439 callback.Run(status); 440 return; 441 } 442 443 if (!entry) { 444 NOTREACHED(); 445 callback.Run(SYNC_STATUS_FAILED); 446 return; 447 } 448 449 DCHECK(entry); 450 metadata_database()->UpdateByFileResource( 451 *drive::util::ConvertResourceEntryToFileResource(*entry), 452 base::Bind(&LocalToRemoteSyncer::DidUpdateDatabaseForUploadExistingFile, 453 weak_ptr_factory_.GetWeakPtr(), 454 callback)); 455} 456 457void LocalToRemoteSyncer::DidUpdateDatabaseForUploadExistingFile( 458 const SyncStatusCallback& callback, 459 SyncStatusCode status) { 460 if (status != SYNC_STATUS_OK) { 461 callback.Run(status); 462 return; 463 } 464 465 FileMetadata file; 466 bool should_success = metadata_database()->FindFileByFileID( 467 remote_file_tracker_->file_id(), &file); 468 if (!should_success) { 469 NOTREACHED(); 470 callback.Run(SYNC_STATUS_FAILED); 471 return; 472 } 473 474 const FileDetails& details = file.details(); 475 base::FilePath title = fileapi::VirtualPath::BaseName(target_path_); 476 if (!details.missing() && 477 details.file_kind() == FILE_KIND_FILE && 478 details.title() == title.AsUTF8Unsafe() && 479 HasFileAsParent(details, 480 remote_parent_folder_tracker_->file_id())) { 481 metadata_database()->UpdateTracker( 482 remote_file_tracker_->tracker_id(), 483 file.details(), 484 callback); 485 return; 486 } 487 488 callback.Run(SYNC_STATUS_RETRY); 489} 490 491void LocalToRemoteSyncer::UpdateRemoteMetadata( 492 const std::string& file_id, 493 const SyncStatusCallback& callback) { 494 DCHECK(remote_file_tracker_); 495 drive_service()->GetResourceEntry( 496 file_id, 497 base::Bind(&LocalToRemoteSyncer::DidGetRemoteMetadata, 498 weak_ptr_factory_.GetWeakPtr(), 499 file_id, callback)); 500} 501 502void LocalToRemoteSyncer::DidGetRemoteMetadata( 503 const std::string& file_id, 504 const SyncStatusCallback& callback, 505 google_apis::GDataErrorCode error, 506 scoped_ptr<google_apis::ResourceEntry> entry) { 507 if (error == google_apis::HTTP_NOT_FOUND) { 508 metadata_database()->UpdateByDeletedRemoteFile(file_id, callback); 509 return; 510 } 511 512 SyncStatusCode status = GDataErrorCodeToSyncStatusCode(error); 513 if (status != SYNC_STATUS_OK) { 514 callback.Run(status); 515 return; 516 } 517 518 if (!entry) { 519 NOTREACHED(); 520 callback.Run(SYNC_STATUS_FAILED); 521 return; 522 } 523 524 metadata_database()->UpdateByFileResource( 525 *drive::util::ConvertResourceEntryToFileResource(*entry), callback); 526} 527 528void LocalToRemoteSyncer::DidDeleteForUploadNewFile( 529 const SyncStatusCallback& callback, 530 SyncStatusCode status) { 531 if (status == SYNC_STATUS_HAS_CONFLICT) { 532 UpdateRemoteMetadata(remote_file_tracker_->file_id(), 533 base::Bind(&ReturnRetryOnSuccess, callback)); 534 return; 535 } 536 537 if (status != SYNC_STATUS_OK) { 538 callback.Run(status); 539 return; 540 } 541 542 UploadNewFile(callback); 543} 544 545void LocalToRemoteSyncer::DidDeleteForCreateFolder( 546 const SyncStatusCallback& callback, 547 SyncStatusCode status) { 548 if (status == SYNC_STATUS_HAS_CONFLICT) { 549 UpdateRemoteMetadata(remote_file_tracker_->file_id(), 550 base::Bind(&ReturnRetryOnSuccess, callback)); 551 return; 552 } 553 554 if (status != SYNC_STATUS_OK) { 555 callback.Run(status); 556 return; 557 } 558 559 CreateRemoteFolder(callback); 560} 561 562void LocalToRemoteSyncer::UploadNewFile(const SyncStatusCallback& callback) { 563 DCHECK(remote_parent_folder_tracker_); 564 565 sync_action_ = SYNC_ACTION_ADDED; 566 base::FilePath title = fileapi::VirtualPath::BaseName(target_path_); 567 drive_uploader()->UploadNewFile( 568 remote_parent_folder_tracker_->file_id(), 569 local_path_, 570 title.AsUTF8Unsafe(), 571 GetMimeTypeFromTitle(title), 572 drive::DriveUploader::UploadNewFileOptions(), 573 base::Bind(&LocalToRemoteSyncer::DidUploadNewFile, 574 weak_ptr_factory_.GetWeakPtr(), 575 callback), 576 google_apis::ProgressCallback()); 577} 578 579void LocalToRemoteSyncer::DidUploadNewFile( 580 const SyncStatusCallback& callback, 581 google_apis::GDataErrorCode error, 582 const GURL& upload_location, 583 scoped_ptr<google_apis::ResourceEntry> entry) { 584 if (error == google_apis::HTTP_NOT_FOUND) 585 needs_remote_change_listing_ = true; 586 587 SyncStatusCode status = GDataErrorCodeToSyncStatusCode(error); 588 if (status != SYNC_STATUS_OK) { 589 callback.Run(status); 590 return; 591 } 592 593 if (!entry) { 594 NOTREACHED(); 595 callback.Run(SYNC_STATUS_FAILED); 596 return; 597 } 598 599 metadata_database()->ReplaceActiveTrackerWithNewResource( 600 remote_parent_folder_tracker_->tracker_id(), 601 *drive::util::ConvertResourceEntryToFileResource(*entry), 602 callback); 603} 604 605void LocalToRemoteSyncer::CreateRemoteFolder( 606 const SyncStatusCallback& callback) { 607 DCHECK(remote_parent_folder_tracker_); 608 609 base::FilePath title = fileapi::VirtualPath::BaseName(target_path_); 610 sync_action_ = SYNC_ACTION_ADDED; 611 612 DCHECK(!folder_creator_); 613 folder_creator_.reset(new FolderCreator( 614 drive_service(), metadata_database(), 615 remote_parent_folder_tracker_->file_id(), 616 title.AsUTF8Unsafe())); 617 folder_creator_->Run(base::Bind( 618 &LocalToRemoteSyncer::DidCreateRemoteFolder, 619 weak_ptr_factory_.GetWeakPtr(), 620 callback)); 621} 622 623void LocalToRemoteSyncer::DidCreateRemoteFolder( 624 const SyncStatusCallback& callback, 625 const std::string& file_id, 626 SyncStatusCode status) { 627 if (status == SYNC_FILE_ERROR_NOT_FOUND) 628 needs_remote_change_listing_ = true; 629 630 scoped_ptr<FolderCreator> deleter = folder_creator_.Pass(); 631 if (status != SYNC_STATUS_OK) { 632 callback.Run(status); 633 return; 634 } 635 636 MetadataDatabase::ActivationStatus activation_status = 637 metadata_database()->TryActivateTracker( 638 remote_parent_folder_tracker_->tracker_id(), 639 file_id, callback); 640 switch (activation_status) { 641 case MetadataDatabase::ACTIVATION_PENDING: 642 // |callback| will be invoked by MetadataDatabase later in this case. 643 return; 644 case MetadataDatabase::ACTIVATION_FAILED_ANOTHER_ACTIVE_TRACKER: 645 // The activation failed due to another tracker that has another parent. 646 // Detach the folder from the current parent to avoid using this folder as 647 // active folder. 648 drive_service()->RemoveResourceFromDirectory( 649 remote_parent_folder_tracker_->file_id(), file_id, 650 base::Bind(&LocalToRemoteSyncer::DidDetachResourceForCreationConflict, 651 weak_ptr_factory_.GetWeakPtr(), 652 callback)); 653 return; 654 } 655 656 NOTREACHED(); 657 callback.Run(SYNC_STATUS_FAILED); 658 return; 659} 660 661void LocalToRemoteSyncer::DidDetachResourceForCreationConflict( 662 const SyncStatusCallback& callback, 663 google_apis::GDataErrorCode error) { 664 SyncStatusCode status = GDataErrorCodeToSyncStatusCode(error); 665 if (status != SYNC_STATUS_OK) { 666 callback.Run(status); 667 return; 668 } 669 670 callback.Run(SYNC_STATUS_RETRY); 671} 672 673bool LocalToRemoteSyncer::IsContextReady() { 674 return sync_context_->GetDriveService() && 675 sync_context_->GetDriveUploader() && 676 sync_context_->GetMetadataDatabase(); 677} 678 679drive::DriveServiceInterface* LocalToRemoteSyncer::drive_service() { 680 set_used_network(true); 681 return sync_context_->GetDriveService(); 682} 683 684drive::DriveUploaderInterface* LocalToRemoteSyncer::drive_uploader() { 685 set_used_network(true); 686 return sync_context_->GetDriveUploader(); 687} 688 689MetadataDatabase* LocalToRemoteSyncer::metadata_database() { 690 return sync_context_->GetMetadataDatabase(); 691} 692 693} // namespace drive_backend 694} // namespace sync_file_system 695