local_to_remote_syncer.cc revision 46d4c2bc3267f3f028f39e7e311b0f89aba2e4fd
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/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/drive_backend_util.h" 21#include "chrome/browser/sync_file_system/drive_backend/folder_creator.h" 22#include "chrome/browser/sync_file_system/drive_backend/metadata_database.h" 23#include "chrome/browser/sync_file_system/drive_backend/metadata_database.pb.h" 24#include "chrome/browser/sync_file_system/drive_backend/sync_engine_context.h" 25#include "chrome/browser/sync_file_system/drive_backend/sync_task_manager.h" 26#include "chrome/browser/sync_file_system/drive_backend/sync_task_token.h" 27#include "chrome/browser/sync_file_system/logger.h" 28#include "google_apis/drive/drive_api_parser.h" 29#include "webkit/common/fileapi/file_system_util.h" 30 31namespace sync_file_system { 32namespace drive_backend { 33 34namespace { 35 36scoped_ptr<FileTracker> FindTrackerByID(MetadataDatabase* metadata_database, 37 int64 tracker_id) { 38 scoped_ptr<FileTracker> tracker(new FileTracker); 39 if (metadata_database->FindTrackerByTrackerID(tracker_id, tracker.get())) 40 return tracker.Pass(); 41 return scoped_ptr<FileTracker>(); 42} 43 44void ReturnRetryOnSuccess(const SyncStatusCallback& callback, 45 SyncStatusCode status) { 46 if (status == SYNC_STATUS_OK) 47 status = SYNC_STATUS_RETRY; 48 callback.Run(status); 49} 50 51bool IsLocalFileMissing(const SyncFileMetadata& local_metadata, 52 const FileChange& local_change) { 53 return local_metadata.file_type == SYNC_FILE_TYPE_UNKNOWN || 54 local_change.IsDelete(); 55} 56 57} // namespace 58 59LocalToRemoteSyncer::LocalToRemoteSyncer(SyncEngineContext* sync_context, 60 const SyncFileMetadata& local_metadata, 61 const FileChange& local_change, 62 const base::FilePath& local_path, 63 const fileapi::FileSystemURL& url) 64 : sync_context_(sync_context), 65 local_change_(local_change), 66 local_is_missing_(IsLocalFileMissing(local_metadata, local_change)), 67 local_path_(local_path), 68 url_(url), 69 sync_action_(SYNC_ACTION_NONE), 70 needs_remote_change_listing_(false), 71 weak_ptr_factory_(this) { 72 DCHECK(local_is_missing_ || 73 local_change.file_type() == local_metadata.file_type) 74 << local_change.DebugString() << " metadata:" << local_metadata.file_type; 75} 76 77LocalToRemoteSyncer::~LocalToRemoteSyncer() { 78} 79 80void LocalToRemoteSyncer::RunPreflight(scoped_ptr<SyncTaskToken> token) { 81 token->InitializeTaskLog("Local -> Remote"); 82 83 scoped_ptr<BlockingFactor> blocking_factor(new BlockingFactor); 84 blocking_factor->exclusive = true; 85 SyncTaskManager::UpdateBlockingFactor( 86 token.Pass(), blocking_factor.Pass(), 87 base::Bind(&LocalToRemoteSyncer::RunExclusive, 88 weak_ptr_factory_.GetWeakPtr())); 89} 90 91void LocalToRemoteSyncer::RunExclusive(scoped_ptr<SyncTaskToken> token) { 92 if (!IsContextReady()) { 93 token->RecordLog("Context not ready."); 94 NOTREACHED(); 95 SyncTaskManager::NotifyTaskDone(token.Pass(), SYNC_STATUS_FAILED); 96 return; 97 } 98 99 token->RecordLog(base::StringPrintf( 100 "Start: %s on %s@%s %s", 101 local_change_.DebugString().c_str(), 102 url_.path().AsUTF8Unsafe().c_str(), 103 url_.origin().host().c_str(), 104 local_is_missing_ ? "(missing)" : "")); 105 106 if (local_is_missing_ && !local_change_.IsDelete()) { 107 // Stray file, we can just return. 108 token->RecordLog("Missing file for non-delete change."); 109 SyncTaskManager::NotifyTaskDone(token.Pass(), SYNC_STATUS_OK); 110 return; 111 } 112 113 std::string app_id = url_.origin().host(); 114 base::FilePath path = url_.path(); 115 116 scoped_ptr<FileTracker> active_ancestor_tracker(new FileTracker); 117 base::FilePath active_ancestor_path; 118 if (!metadata_database()->FindNearestActiveAncestor( 119 app_id, path, 120 active_ancestor_tracker.get(), &active_ancestor_path)) { 121 // The app is disabled or not registered. 122 token->RecordLog("App is disabled or not registered"); 123 SyncTaskManager::NotifyTaskDone(token.Pass(), SYNC_STATUS_UNKNOWN_ORIGIN); 124 return; 125 } 126 DCHECK(active_ancestor_tracker->active()); 127 DCHECK(active_ancestor_tracker->has_synced_details()); 128 const FileDetails& active_ancestor_details = 129 active_ancestor_tracker->synced_details(); 130 131 // TODO(tzik): Consider handling 132 // active_ancestor_tracker->synced_details().missing() case. 133 134 DCHECK(active_ancestor_details.file_kind() == FILE_KIND_FILE || 135 active_ancestor_details.file_kind() == FILE_KIND_FOLDER); 136 137 base::FilePath missing_entries; 138 if (active_ancestor_path.empty()) { 139 missing_entries = path; 140 } else if (active_ancestor_path != path) { 141 if (!active_ancestor_path.AppendRelativePath(path, &missing_entries)) { 142 NOTREACHED(); 143 token->RecordLog(base::StringPrintf( 144 "Detected invalid ancestor: %s", 145 active_ancestor_path.value().c_str())); 146 SyncTaskManager::NotifyTaskDone(token.Pass(), SYNC_STATUS_FAILED); 147 return; 148 } 149 } 150 151 std::vector<base::FilePath::StringType> missing_components; 152 fileapi::VirtualPath::GetComponents(missing_entries, &missing_components); 153 154 if (!missing_components.empty()) { 155 if (local_is_missing_) { 156 token->RecordLog("Both local and remote are marked missing"); 157 // !IsDelete() but SYNC_FILE_TYPE_UNKNOWN could happen when a file is 158 // deleted by recursive deletion (which is not recorded by tracker) 159 // but there're remaining changes for the same file in the tracker. 160 161 // Local file is deleted and remote file is missing, already deleted or 162 // not yet synced. There is nothing to do for the file. 163 SyncTaskManager::NotifyTaskDone(token.Pass(), SYNC_STATUS_OK); 164 return; 165 } 166 } 167 168 if (missing_components.size() > 1) { 169 // The original target doesn't have remote file and parent. 170 // Try creating the parent first. 171 if (active_ancestor_details.file_kind() == FILE_KIND_FOLDER) { 172 remote_parent_folder_tracker_ = active_ancestor_tracker.Pass(); 173 target_path_ = active_ancestor_path.Append(missing_components[0]); 174 token->RecordLog("Detected missing parent folder."); 175 CreateRemoteFolder(base::Bind( 176 &LocalToRemoteSyncer::SyncCompleted, weak_ptr_factory_.GetWeakPtr(), 177 base::Passed(&token))); 178 return; 179 } 180 181 DCHECK(active_ancestor_details.file_kind() == FILE_KIND_FILE); 182 remote_parent_folder_tracker_ = 183 FindTrackerByID(metadata_database(), 184 active_ancestor_tracker->parent_tracker_id()); 185 remote_file_tracker_ = active_ancestor_tracker.Pass(); 186 target_path_ = active_ancestor_path; 187 token->RecordLog("Detected non-folder file in its path."); 188 DeleteRemoteFile(base::Bind( 189 &LocalToRemoteSyncer::DidDeleteForCreateFolder, 190 weak_ptr_factory_.GetWeakPtr(), 191 base::Bind(&LocalToRemoteSyncer::SyncCompleted, 192 weak_ptr_factory_.GetWeakPtr(), base::Passed(&token)))); 193 return; 194 } 195 196 if (missing_components.empty()) { 197 // The original target has remote active file/folder. 198 remote_parent_folder_tracker_ = 199 FindTrackerByID(metadata_database(), 200 active_ancestor_tracker->parent_tracker_id()); 201 remote_file_tracker_ = active_ancestor_tracker.Pass(); 202 target_path_ = url_.path(); 203 DCHECK(target_path_ == active_ancestor_path); 204 205 if (remote_file_tracker_->dirty()) { 206 token->RecordLog(base::StringPrintf( 207 "Detected conflicting dirty tracker:%" PRId64, 208 remote_file_tracker_->tracker_id())); 209 // Both local and remote file has pending modification. 210 HandleConflict(base::Bind( 211 &LocalToRemoteSyncer::SyncCompleted, 212 weak_ptr_factory_.GetWeakPtr(), base::Passed(&token))); 213 return; 214 } 215 216 // Non-conflicting file/folder update case. 217 HandleExistingRemoteFile(base::Bind( 218 &LocalToRemoteSyncer::SyncCompleted, weak_ptr_factory_.GetWeakPtr(), 219 base::Passed(&token))); 220 return; 221 } 222 223 DCHECK(local_change_.IsAddOrUpdate()); 224 DCHECK_EQ(1u, missing_components.size()); 225 // The original target has remote parent folder and doesn't have remote active 226 // file. 227 // Upload the file as a new file or create a folder. 228 remote_parent_folder_tracker_ = active_ancestor_tracker.Pass(); 229 target_path_ = url_.path(); 230 DCHECK(target_path_ == active_ancestor_path.Append(missing_components[0])); 231 if (local_change_.file_type() == SYNC_FILE_TYPE_FILE) { 232 token->RecordLog("Detected a new file."); 233 UploadNewFile(base::Bind( 234 &LocalToRemoteSyncer::SyncCompleted, 235 weak_ptr_factory_.GetWeakPtr(), base::Passed(&token))); 236 return; 237 } 238 239 token->RecordLog("Detected a new folder."); 240 CreateRemoteFolder(base::Bind( 241 &LocalToRemoteSyncer::SyncCompleted, 242 weak_ptr_factory_.GetWeakPtr(), base::Passed(&token))); 243} 244 245void LocalToRemoteSyncer::SyncCompleted(scoped_ptr<SyncTaskToken> token, 246 SyncStatusCode status) { 247 if (status == SYNC_STATUS_OK && target_path_ != url_.path()) 248 status = SYNC_STATUS_RETRY; 249 250 if (needs_remote_change_listing_) 251 status = SYNC_STATUS_FILE_BUSY; 252 253 util::Log(logging::LOG_VERBOSE, FROM_HERE, 254 "[Local -> Remote]: Finished: action=%s, status=%s for %s@%s", 255 SyncActionToString(sync_action_), 256 SyncStatusCodeToString(status), 257 target_path_.AsUTF8Unsafe().c_str(), 258 url_.origin().host().c_str()); 259 260 SyncTaskManager::NotifyTaskDone(token.Pass(), status); 261} 262 263void LocalToRemoteSyncer::HandleConflict(const SyncStatusCallback& callback) { 264 DCHECK(remote_file_tracker_); 265 DCHECK(remote_file_tracker_->has_synced_details()); 266 DCHECK(remote_file_tracker_->active()); 267 DCHECK(remote_file_tracker_->dirty()); 268 269 if (local_is_missing_) { 270 callback.Run(SYNC_STATUS_OK); 271 return; 272 } 273 274 if (local_change_.IsFile()) { 275 UploadNewFile(callback); 276 return; 277 } 278 279 DCHECK(local_change_.IsDirectory()); 280 // Check if we can reuse the remote folder. 281 FileMetadata remote_file_metadata; 282 if (!metadata_database()->FindFileByFileID( 283 remote_file_tracker_->file_id(), &remote_file_metadata)) { 284 NOTREACHED(); 285 CreateRemoteFolder(callback); 286 return; 287 } 288 289 const FileDetails& remote_details = remote_file_metadata.details(); 290 base::FilePath title = fileapi::VirtualPath::BaseName(target_path_); 291 if (!remote_details.missing() && 292 remote_details.file_kind() == FILE_KIND_FOLDER && 293 remote_details.title() == title.AsUTF8Unsafe() && 294 HasFileAsParent(remote_details, 295 remote_parent_folder_tracker_->file_id())) { 296 metadata_database()->UpdateTracker( 297 remote_file_tracker_->tracker_id(), remote_details, callback); 298 return; 299 } 300 301 // Create new remote folder. 302 CreateRemoteFolder(callback); 303} 304 305void LocalToRemoteSyncer::HandleExistingRemoteFile( 306 const SyncStatusCallback& callback) { 307 DCHECK(remote_file_tracker_); 308 DCHECK(!remote_file_tracker_->dirty()); 309 DCHECK(remote_file_tracker_->active()); 310 DCHECK(remote_file_tracker_->has_synced_details()); 311 312 if (local_is_missing_) { 313 // Local file deletion for existing remote file. 314 DeleteRemoteFile(callback); 315 return; 316 } 317 318 DCHECK(local_change_.IsAddOrUpdate()); 319 DCHECK(local_change_.IsFile() || local_change_.IsDirectory()); 320 321 const FileDetails& synced_details = remote_file_tracker_->synced_details(); 322 DCHECK(synced_details.file_kind() == FILE_KIND_FILE || 323 synced_details.file_kind() == FILE_KIND_FOLDER); 324 if (local_change_.IsFile()) { 325 if (synced_details.file_kind() == FILE_KIND_FILE) { 326 // Non-conflicting local file update to existing remote regular file. 327 UploadExistingFile(callback); 328 return; 329 } 330 331 DCHECK_EQ(FILE_KIND_FOLDER, synced_details.file_kind()); 332 // Non-conflicting local file update to existing remote *folder*. 333 // Assuming this case as local folder deletion + local file creation, delete 334 // the remote folder and upload the file. 335 DeleteRemoteFile(base::Bind(&LocalToRemoteSyncer::DidDeleteForUploadNewFile, 336 weak_ptr_factory_.GetWeakPtr(), 337 callback)); 338 return; 339 } 340 341 DCHECK(local_change_.IsDirectory()); 342 if (synced_details.file_kind() == FILE_KIND_FILE) { 343 // Non-conflicting local folder creation to existing remote *file*. 344 // Assuming this case as local file deletion + local folder creation, delete 345 // the remote file and create a remote folder. 346 DeleteRemoteFile(base::Bind(&LocalToRemoteSyncer::DidDeleteForCreateFolder, 347 weak_ptr_factory_.GetWeakPtr(), callback)); 348 return; 349 } 350 351 // Non-conflicting local folder creation to existing remote folder. 352 DCHECK_EQ(FILE_KIND_FOLDER, synced_details.file_kind()); 353 callback.Run(SYNC_STATUS_OK); 354} 355 356void LocalToRemoteSyncer::DeleteRemoteFile( 357 const SyncStatusCallback& callback) { 358 DCHECK(remote_file_tracker_); 359 DCHECK(remote_file_tracker_->has_synced_details()); 360 361 sync_action_ = SYNC_ACTION_DELETED; 362 drive_service()->DeleteResource( 363 remote_file_tracker_->file_id(), 364 remote_file_tracker_->synced_details().etag(), 365 base::Bind(&LocalToRemoteSyncer::DidDeleteRemoteFile, 366 weak_ptr_factory_.GetWeakPtr(), 367 callback)); 368} 369 370void LocalToRemoteSyncer::DidDeleteRemoteFile( 371 const SyncStatusCallback& callback, 372 google_apis::GDataErrorCode error) { 373 SyncStatusCode status = GDataErrorCodeToSyncStatusCode(error); 374 if (status != SYNC_STATUS_OK && 375 error != google_apis::HTTP_NOT_FOUND && 376 error != google_apis::HTTP_PRECONDITION && 377 error != google_apis::HTTP_CONFLICT) { 378 callback.Run(status); 379 return; 380 } 381 382 // Handle NOT_FOUND case as SUCCESS case. 383 // For PRECONDITION / CONFLICT case, the remote file is modified since the 384 // last sync completed. As our policy for deletion-modification conflict 385 // resolution, ignore the local deletion. 386 if (error == google_apis::HTTP_NOT_FOUND) { 387 metadata_database()->UpdateByDeletedRemoteFile( 388 remote_file_tracker_->file_id(), callback); 389 return; 390 } 391 callback.Run(SYNC_STATUS_OK); 392} 393 394void LocalToRemoteSyncer::UploadExistingFile( 395 const SyncStatusCallback& callback) { 396 DCHECK(remote_file_tracker_); 397 DCHECK(remote_file_tracker_->has_synced_details()); 398 399 base::PostTaskAndReplyWithResult( 400 sync_context_->GetFileTaskRunner(), FROM_HERE, 401 base::Bind(&drive::util::GetMd5Digest, local_path_), 402 base::Bind(&LocalToRemoteSyncer::DidGetMD5ForUpload, 403 weak_ptr_factory_.GetWeakPtr(), 404 callback)); 405} 406 407void LocalToRemoteSyncer::DidGetMD5ForUpload( 408 const SyncStatusCallback& callback, 409 const std::string& local_file_md5) { 410 if (local_file_md5 == remote_file_tracker_->synced_details().md5()) { 411 // Local file is not changed. 412 callback.Run(SYNC_STATUS_OK); 413 return; 414 } 415 416 sync_action_ = SYNC_ACTION_UPDATED; 417 418 drive::DriveUploader::UploadExistingFileOptions options; 419 options.etag = remote_file_tracker_->synced_details().etag(); 420 drive_uploader()->UploadExistingFile( 421 remote_file_tracker_->file_id(), 422 local_path_, 423 "application/octet_stream", 424 options, 425 base::Bind(&LocalToRemoteSyncer::DidUploadExistingFile, 426 weak_ptr_factory_.GetWeakPtr(), 427 callback), 428 google_apis::ProgressCallback()); 429} 430 431void LocalToRemoteSyncer::DidUploadExistingFile( 432 const SyncStatusCallback& callback, 433 google_apis::GDataErrorCode error, 434 const GURL&, 435 scoped_ptr<google_apis::FileResource> entry) { 436 if (error == google_apis::HTTP_PRECONDITION || 437 error == google_apis::HTTP_CONFLICT || 438 error == google_apis::HTTP_NOT_FOUND) { 439 // The remote file has unfetched remote change. Fetch latest metadata and 440 // update database with it. 441 // TODO(tzik): Consider adding local side low-priority dirtiness handling to 442 // handle this as ListChangesTask. 443 444 needs_remote_change_listing_ = true; 445 UpdateRemoteMetadata(remote_file_tracker_->file_id(), 446 base::Bind(&ReturnRetryOnSuccess, callback)); 447 return; 448 } 449 450 SyncStatusCode status = GDataErrorCodeToSyncStatusCode(error); 451 if (status != SYNC_STATUS_OK) { 452 callback.Run(status); 453 return; 454 } 455 456 if (!entry) { 457 NOTREACHED(); 458 callback.Run(SYNC_STATUS_FAILED); 459 return; 460 } 461 462 DCHECK(entry); 463 metadata_database()->UpdateByFileResource( 464 *entry, 465 base::Bind(&LocalToRemoteSyncer::DidUpdateDatabaseForUploadExistingFile, 466 weak_ptr_factory_.GetWeakPtr(), 467 callback)); 468} 469 470void LocalToRemoteSyncer::DidUpdateDatabaseForUploadExistingFile( 471 const SyncStatusCallback& callback, 472 SyncStatusCode status) { 473 if (status != SYNC_STATUS_OK) { 474 callback.Run(status); 475 return; 476 } 477 478 FileMetadata file; 479 if (!metadata_database()->FindFileByFileID( 480 remote_file_tracker_->file_id(), &file)) { 481 NOTREACHED(); 482 callback.Run(SYNC_STATUS_FAILED); 483 return; 484 } 485 486 const FileDetails& details = file.details(); 487 base::FilePath title = fileapi::VirtualPath::BaseName(target_path_); 488 if (!details.missing() && 489 details.file_kind() == FILE_KIND_FILE && 490 details.title() == title.AsUTF8Unsafe() && 491 HasFileAsParent(details, 492 remote_parent_folder_tracker_->file_id())) { 493 metadata_database()->UpdateTracker( 494 remote_file_tracker_->tracker_id(), 495 file.details(), 496 callback); 497 return; 498 } 499 500 callback.Run(SYNC_STATUS_RETRY); 501} 502 503void LocalToRemoteSyncer::UpdateRemoteMetadata( 504 const std::string& file_id, 505 const SyncStatusCallback& callback) { 506 DCHECK(remote_file_tracker_); 507 508 drive_service()->GetFileResource( 509 file_id, 510 base::Bind(&LocalToRemoteSyncer::DidGetRemoteMetadata, 511 weak_ptr_factory_.GetWeakPtr(), 512 file_id, callback)); 513} 514 515void LocalToRemoteSyncer::DidGetRemoteMetadata( 516 const std::string& file_id, 517 const SyncStatusCallback& callback, 518 google_apis::GDataErrorCode error, 519 scoped_ptr<google_apis::FileResource> entry) { 520 DCHECK(sync_context_->GetWorkerTaskRunner()->RunsTasksOnCurrentThread()); 521 522 if (error == google_apis::HTTP_NOT_FOUND) { 523 metadata_database()->UpdateByDeletedRemoteFile(file_id, callback); 524 return; 525 } 526 527 SyncStatusCode status = GDataErrorCodeToSyncStatusCode(error); 528 if (status != SYNC_STATUS_OK) { 529 callback.Run(status); 530 return; 531 } 532 533 if (!entry) { 534 NOTREACHED(); 535 callback.Run(SYNC_STATUS_FAILED); 536 return; 537 } 538 539 metadata_database()->UpdateByFileResource(*entry, callback); 540} 541 542void LocalToRemoteSyncer::DidDeleteForUploadNewFile( 543 const SyncStatusCallback& callback, 544 SyncStatusCode status) { 545 if (status == SYNC_STATUS_HAS_CONFLICT) { 546 UpdateRemoteMetadata(remote_file_tracker_->file_id(), 547 base::Bind(&ReturnRetryOnSuccess, callback)); 548 return; 549 } 550 551 if (status != SYNC_STATUS_OK) { 552 callback.Run(status); 553 return; 554 } 555 556 UploadNewFile(callback); 557} 558 559void LocalToRemoteSyncer::DidDeleteForCreateFolder( 560 const SyncStatusCallback& callback, 561 SyncStatusCode status) { 562 if (status == SYNC_STATUS_HAS_CONFLICT) { 563 UpdateRemoteMetadata(remote_file_tracker_->file_id(), 564 base::Bind(&ReturnRetryOnSuccess, callback)); 565 return; 566 } 567 568 if (status != SYNC_STATUS_OK) { 569 callback.Run(status); 570 return; 571 } 572 573 CreateRemoteFolder(callback); 574} 575 576void LocalToRemoteSyncer::UploadNewFile(const SyncStatusCallback& callback) { 577 DCHECK(remote_parent_folder_tracker_); 578 579 sync_action_ = SYNC_ACTION_ADDED; 580 base::FilePath title = fileapi::VirtualPath::BaseName(target_path_); 581 drive_uploader()->UploadNewFile( 582 remote_parent_folder_tracker_->file_id(), 583 local_path_, 584 title.AsUTF8Unsafe(), 585 GetMimeTypeFromTitle(title), 586 drive::DriveUploader::UploadNewFileOptions(), 587 base::Bind(&LocalToRemoteSyncer::DidUploadNewFile, 588 weak_ptr_factory_.GetWeakPtr(), 589 callback), 590 google_apis::ProgressCallback()); 591} 592 593void LocalToRemoteSyncer::DidUploadNewFile( 594 const SyncStatusCallback& callback, 595 google_apis::GDataErrorCode error, 596 const GURL& upload_location, 597 scoped_ptr<google_apis::FileResource> entry) { 598 if (error == google_apis::HTTP_NOT_FOUND) 599 needs_remote_change_listing_ = true; 600 601 SyncStatusCode status = GDataErrorCodeToSyncStatusCode(error); 602 if (status != SYNC_STATUS_OK) { 603 callback.Run(status); 604 return; 605 } 606 607 if (!entry) { 608 NOTREACHED(); 609 callback.Run(SYNC_STATUS_FAILED); 610 return; 611 } 612 613 metadata_database()->ReplaceActiveTrackerWithNewResource( 614 remote_parent_folder_tracker_->tracker_id(), *entry, callback); 615} 616 617void LocalToRemoteSyncer::CreateRemoteFolder( 618 const SyncStatusCallback& callback) { 619 DCHECK(remote_parent_folder_tracker_); 620 621 base::FilePath title = fileapi::VirtualPath::BaseName(target_path_); 622 sync_action_ = SYNC_ACTION_ADDED; 623 624 DCHECK(!folder_creator_); 625 folder_creator_.reset(new FolderCreator( 626 drive_service(), metadata_database(), 627 remote_parent_folder_tracker_->file_id(), 628 title.AsUTF8Unsafe())); 629 folder_creator_->Run(base::Bind( 630 &LocalToRemoteSyncer::DidCreateRemoteFolder, 631 weak_ptr_factory_.GetWeakPtr(), 632 callback)); 633} 634 635void LocalToRemoteSyncer::DidCreateRemoteFolder( 636 const SyncStatusCallback& callback, 637 const std::string& file_id, 638 SyncStatusCode status) { 639 if (status == SYNC_FILE_ERROR_NOT_FOUND) 640 needs_remote_change_listing_ = true; 641 642 scoped_ptr<FolderCreator> deleter = folder_creator_.Pass(); 643 if (status != SYNC_STATUS_OK) { 644 callback.Run(status); 645 return; 646 } 647 648 MetadataDatabase::ActivationStatus activation_status = 649 metadata_database()->TryActivateTracker( 650 remote_parent_folder_tracker_->tracker_id(), 651 file_id, callback); 652 switch (activation_status) { 653 case MetadataDatabase::ACTIVATION_PENDING: 654 // |callback| will be invoked by MetadataDatabase later in this case. 655 return; 656 case MetadataDatabase::ACTIVATION_FAILED_ANOTHER_ACTIVE_TRACKER: 657 // The activation failed due to another tracker that has another parent. 658 // Detach the folder from the current parent to avoid using this folder as 659 // active folder. 660 drive_service()->RemoveResourceFromDirectory( 661 remote_parent_folder_tracker_->file_id(), file_id, 662 base::Bind(&LocalToRemoteSyncer::DidDetachResourceForCreationConflict, 663 weak_ptr_factory_.GetWeakPtr(), 664 callback)); 665 return; 666 } 667 668 NOTREACHED(); 669 callback.Run(SYNC_STATUS_FAILED); 670 return; 671} 672 673void LocalToRemoteSyncer::DidDetachResourceForCreationConflict( 674 const SyncStatusCallback& callback, 675 google_apis::GDataErrorCode error) { 676 SyncStatusCode status = GDataErrorCodeToSyncStatusCode(error); 677 if (status != SYNC_STATUS_OK) { 678 callback.Run(status); 679 return; 680 } 681 682 callback.Run(SYNC_STATUS_RETRY); 683} 684 685bool LocalToRemoteSyncer::IsContextReady() { 686 return sync_context_->GetDriveService() && 687 sync_context_->GetDriveUploader() && 688 sync_context_->GetMetadataDatabase(); 689} 690 691drive::DriveServiceInterface* LocalToRemoteSyncer::drive_service() { 692 set_used_network(true); 693 return sync_context_->GetDriveService(); 694} 695 696drive::DriveUploaderInterface* LocalToRemoteSyncer::drive_uploader() { 697 set_used_network(true); 698 return sync_context_->GetDriveUploader(); 699} 700 701MetadataDatabase* LocalToRemoteSyncer::metadata_database() { 702 return sync_context_->GetMetadataDatabase(); 703} 704 705} // namespace drive_backend 706} // namespace sync_file_system 707