remote_to_local_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/remote_to_local_syncer.h" 6 7#include "base/bind.h" 8#include "base/callback.h" 9#include "base/format_macros.h" 10#include "base/location.h" 11#include "base/logging.h" 12#include "base/message_loop/message_loop_proxy.h" 13#include "base/task_runner_util.h" 14#include "chrome/browser/drive/drive_api_util.h" 15#include "chrome/browser/drive/drive_service_interface.h" 16#include "chrome/browser/sync_file_system/drive_backend/drive_backend_util.h" 17#include "chrome/browser/sync_file_system/drive_backend/metadata_database.h" 18#include "chrome/browser/sync_file_system/drive_backend/sync_engine_context.h" 19#include "chrome/browser/sync_file_system/logger.h" 20#include "chrome/browser/sync_file_system/syncable_file_system_util.h" 21#include "extensions/common/extension.h" 22#include "google_apis/drive/drive_api_parser.h" 23#include "google_apis/drive/gdata_wapi_parser.h" 24#include "webkit/common/fileapi/file_system_util.h" 25 26namespace sync_file_system { 27namespace drive_backend { 28 29namespace { 30 31bool BuildFileSystemURL( 32 MetadataDatabase* metadata_database, 33 const FileTracker& tracker, 34 fileapi::FileSystemURL* url) { 35 base::FilePath path; 36 if (!metadata_database->BuildPathForTracker( 37 tracker.tracker_id(), &path)) 38 return false; 39 40 GURL origin = 41 extensions::Extension::GetBaseURLFromExtensionId(tracker.app_id()); 42 *url = sync_file_system::CreateSyncableFileSystemURL(origin, path); 43 44 return true; 45} 46 47bool HasFolderAsParent(const FileDetails& details, 48 const std::string& folder_id) { 49 for (int i = 0; i < details.parent_folder_ids_size(); ++i) { 50 if (details.parent_folder_ids(i) == folder_id) 51 return true; 52 } 53 return false; 54} 55 56bool HasDisabledAppRoot(MetadataDatabase* database, 57 const FileTracker& tracker) { 58 DCHECK(tracker.active()); 59 FileTracker app_root_tracker; 60 if (database->FindAppRootTracker(tracker.app_id(), &app_root_tracker)) { 61 DCHECK(app_root_tracker.tracker_kind() == TRACKER_KIND_APP_ROOT || 62 app_root_tracker.tracker_kind() == TRACKER_KIND_DISABLED_APP_ROOT); 63 return app_root_tracker.tracker_kind() == TRACKER_KIND_DISABLED_APP_ROOT; 64 } 65 return false; 66} 67 68scoped_ptr<FileMetadata> GetFileMetadata(MetadataDatabase* database, 69 const std::string& file_id) { 70 scoped_ptr<FileMetadata> metadata(new FileMetadata); 71 if (!database->FindFileByFileID(file_id, metadata.get())) 72 metadata.reset(); 73 return metadata.Pass(); 74} 75 76} // namespace 77 78RemoteToLocalSyncer::RemoteToLocalSyncer(SyncEngineContext* sync_context) 79 : sync_context_(sync_context), 80 sync_action_(SYNC_ACTION_NONE), 81 prepared_(false), 82 sync_root_deletion_(false), 83 weak_ptr_factory_(this) { 84} 85 86RemoteToLocalSyncer::~RemoteToLocalSyncer() { 87} 88 89void RemoteToLocalSyncer::RunExclusive(const SyncStatusCallback& callback) { 90 if (!drive_service() || !metadata_database() || !remote_change_processor()) { 91 util::Log(logging::LOG_VERBOSE, FROM_HERE, 92 "[Remote -> Local] Context not ready."); 93 NOTREACHED(); 94 callback.Run(SYNC_STATUS_FAILED); 95 return; 96 } 97 98 SyncStatusCallback wrapped_callback = base::Bind( 99 &RemoteToLocalSyncer::SyncCompleted, weak_ptr_factory_.GetWeakPtr(), 100 base::Bind(&RemoteToLocalSyncer::FinalizeSync, 101 weak_ptr_factory_.GetWeakPtr(), 102 callback)); 103 104 dirty_tracker_ = make_scoped_ptr(new FileTracker); 105 if (metadata_database()->GetNormalPriorityDirtyTracker( 106 dirty_tracker_.get())) { 107 util::Log(logging::LOG_VERBOSE, FROM_HERE, 108 "[Remote -> Local] Start: tracker_id=%" PRId64, 109 dirty_tracker_->tracker_id()); 110 ResolveRemoteChange(wrapped_callback); 111 return; 112 } 113 114 util::Log(logging::LOG_VERBOSE, FROM_HERE, 115 "[Remote -> Local] Nothing to do."); 116 sync_context_->GetWorkerTaskRunner()->PostTask( 117 FROM_HERE, 118 base::Bind(callback, SYNC_STATUS_NO_CHANGE_TO_SYNC)); 119} 120 121void RemoteToLocalSyncer::ResolveRemoteChange( 122 const SyncStatusCallback& callback) { 123 DCHECK(dirty_tracker_); 124 remote_metadata_ = GetFileMetadata( 125 metadata_database(), dirty_tracker_->file_id()); 126 127 if (!remote_metadata_ || !remote_metadata_->has_details()) { 128 if (remote_metadata_ && !remote_metadata_->has_details()) { 129 LOG(ERROR) << "Missing details of a remote file: " 130 << remote_metadata_->file_id(); 131 NOTREACHED(); 132 } 133 util::Log(logging::LOG_VERBOSE, FROM_HERE, 134 "[Remote -> Local]: Missing remote metadata case."); 135 HandleMissingRemoteMetadata(callback); 136 return; 137 } 138 139 DCHECK(remote_metadata_); 140 DCHECK(remote_metadata_->has_details()); 141 const FileDetails& remote_details = remote_metadata_->details(); 142 143 if (!dirty_tracker_->active() || 144 HasDisabledAppRoot(metadata_database(), *dirty_tracker_)) { 145 // Handle inactive tracker in SyncCompleted. 146 util::Log(logging::LOG_VERBOSE, FROM_HERE, 147 "[Remote -> Local]: Inactive tracker case."); 148 callback.Run(SYNC_STATUS_OK); 149 return; 150 } 151 152 DCHECK(dirty_tracker_->active()); 153 DCHECK(!HasDisabledAppRoot(metadata_database(), *dirty_tracker_)); 154 155 if (!dirty_tracker_->has_synced_details()) { 156 LOG(ERROR) << "Missing synced_details of an active tracker: " 157 << dirty_tracker_->tracker_id(); 158 NOTREACHED(); 159 callback.Run(SYNC_STATUS_FAILED); 160 return; 161 } 162 163 DCHECK(dirty_tracker_->has_synced_details()); 164 const FileDetails& synced_details = dirty_tracker_->synced_details(); 165 166 if (dirty_tracker_->tracker_id() == 167 metadata_database()->GetSyncRootTrackerID()) { 168 if (remote_details.missing() || 169 synced_details.title() != remote_details.title() || 170 remote_details.parent_folder_ids_size()) { 171 util::Log(logging::LOG_VERBOSE, FROM_HERE, 172 "[Remote -> Local]: Sync-root deletion."); 173 HandleSyncRootDeletion(callback); 174 return; 175 } 176 util::Log(logging::LOG_VERBOSE, FROM_HERE, 177 "[Remote -> Local]: Trivial sync-root change."); 178 callback.Run(SYNC_STATUS_OK); 179 return; 180 } 181 182 DCHECK_NE(dirty_tracker_->tracker_id(), 183 metadata_database()->GetSyncRootTrackerID()); 184 185 if (remote_details.missing()) { 186 if (!synced_details.missing()) { 187 util::Log(logging::LOG_VERBOSE, FROM_HERE, 188 "[Remote -> Local]: Remote file deletion."); 189 HandleDeletion(callback); 190 return; 191 } 192 193 DCHECK(synced_details.missing()); 194 LOG(ERROR) << "Found a stray missing tracker: " 195 << dirty_tracker_->file_id(); 196 NOTREACHED(); 197 callback.Run(SYNC_STATUS_OK); 198 return; 199 } 200 201 // Most of remote_details field is valid from here. 202 DCHECK(!remote_details.missing()); 203 204 if (synced_details.file_kind() != remote_details.file_kind()) { 205 LOG(ERROR) << "Found type mismatch between remote and local file: " 206 << dirty_tracker_->file_id() 207 << " type: (local) " << synced_details.file_kind() 208 << " vs (remote) " << remote_details.file_kind(); 209 NOTREACHED(); 210 callback.Run(SYNC_STATUS_FAILED); 211 return; 212 } 213 DCHECK_EQ(synced_details.file_kind(), remote_details.file_kind()); 214 215 if (synced_details.file_kind() == FILE_KIND_UNSUPPORTED) { 216 LOG(ERROR) << "Found an unsupported active file: " 217 << remote_metadata_->file_id(); 218 NOTREACHED(); 219 callback.Run(SYNC_STATUS_FAILED); 220 return; 221 } 222 DCHECK(remote_details.file_kind() == FILE_KIND_FILE || 223 remote_details.file_kind() == FILE_KIND_FOLDER); 224 225 if (synced_details.title() != remote_details.title()) { 226 // Handle rename as deletion + addition. 227 util::Log(logging::LOG_VERBOSE, FROM_HERE, 228 "[Remote -> Local]: Detected file rename."); 229 Prepare(base::Bind(&RemoteToLocalSyncer::DidPrepareForDeletion, 230 weak_ptr_factory_.GetWeakPtr(), callback)); 231 return; 232 } 233 DCHECK_EQ(synced_details.title(), remote_details.title()); 234 235 FileTracker parent_tracker; 236 if (!metadata_database()->FindTrackerByTrackerID( 237 dirty_tracker_->parent_tracker_id(), &parent_tracker)) { 238 LOG(ERROR) << "Missing parent tracker for a non sync-root tracker: " 239 << dirty_tracker_->file_id(); 240 NOTREACHED(); 241 callback.Run(SYNC_STATUS_FAILED); 242 return; 243 } 244 245 if (!HasFolderAsParent(remote_details, parent_tracker.file_id())) { 246 // Handle reorganize as deletion + addition. 247 util::Log(logging::LOG_VERBOSE, FROM_HERE, 248 "[Remote -> Local]: Detected file reorganize."); 249 Prepare(base::Bind(&RemoteToLocalSyncer::DidPrepareForDeletion, 250 weak_ptr_factory_.GetWeakPtr(), callback)); 251 return; 252 } 253 254 if (synced_details.file_kind() == FILE_KIND_FILE) { 255 if (synced_details.md5() != remote_details.md5()) { 256 util::Log(logging::LOG_VERBOSE, FROM_HERE, 257 "[Remote -> Local]: Detected file content update."); 258 HandleContentUpdate(callback); 259 return; 260 } 261 } else { 262 DCHECK_EQ(FILE_KIND_FOLDER, synced_details.file_kind()); 263 if (synced_details.missing()) { 264 util::Log(logging::LOG_VERBOSE, FROM_HERE, 265 "[Remote -> Local]: Detected folder update."); 266 HandleFolderUpdate(callback); 267 return; 268 } 269 if (dirty_tracker_->needs_folder_listing()) { 270 util::Log(logging::LOG_VERBOSE, FROM_HERE, 271 "[Remote -> Local]: Needs listing folder."); 272 ListFolderContent(callback); 273 return; 274 } 275 callback.Run(SYNC_STATUS_OK); 276 return; 277 } 278 279 util::Log(logging::LOG_VERBOSE, FROM_HERE, 280 "[Remote -> Local]: Trivial file change."); 281 callback.Run(SYNC_STATUS_OK); 282} 283 284void RemoteToLocalSyncer::HandleMissingRemoteMetadata( 285 const SyncStatusCallback& callback) { 286 DCHECK(dirty_tracker_); 287 288 drive_service()->GetFileResource( 289 dirty_tracker_->file_id(), 290 base::Bind(&RemoteToLocalSyncer::DidGetRemoteMetadata, 291 weak_ptr_factory_.GetWeakPtr(), 292 callback)); 293} 294 295void RemoteToLocalSyncer::DidGetRemoteMetadata( 296 const SyncStatusCallback& callback, 297 google_apis::GDataErrorCode error, 298 scoped_ptr<google_apis::FileResource> entry) { 299 DCHECK(sync_context_->GetWorkerTaskRunner()->RunsTasksOnCurrentThread()); 300 301 SyncStatusCode status = GDataErrorCodeToSyncStatusCode(error); 302 if (status != SYNC_STATUS_OK && 303 error != google_apis::HTTP_NOT_FOUND) { 304 callback.Run(status); 305 return; 306 } 307 308 if (error == google_apis::HTTP_NOT_FOUND) { 309 metadata_database()->UpdateByDeletedRemoteFile( 310 dirty_tracker_->file_id(), callback); 311 return; 312 } 313 314 if (!entry) { 315 NOTREACHED(); 316 callback.Run(SYNC_STATUS_FAILED); 317 return; 318 } 319 320 metadata_database()->UpdateByFileResource( 321 *entry, 322 base::Bind(&RemoteToLocalSyncer::DidUpdateDatabaseForRemoteMetadata, 323 weak_ptr_factory_.GetWeakPtr(), callback)); 324} 325 326void RemoteToLocalSyncer::DidUpdateDatabaseForRemoteMetadata( 327 const SyncStatusCallback& callback, 328 SyncStatusCode status) { 329 if (status != SYNC_STATUS_OK) { 330 callback.Run(status); 331 return; 332 } 333 334 callback.Run(SYNC_STATUS_RETRY); // Do not update |dirty_tracker_|. 335} 336 337void RemoteToLocalSyncer::DidPrepareForAddOrUpdateFile( 338 const SyncStatusCallback& callback, 339 SyncStatusCode status) { 340 if (status != SYNC_STATUS_OK) { 341 callback.Run(status); 342 return; 343 } 344 345 DCHECK(url_.is_valid()); 346 DCHECK(local_metadata_); 347 DCHECK(local_changes_); 348 349 // Check if the local file exists. 350 if (local_metadata_->file_type == SYNC_FILE_TYPE_UNKNOWN || 351 (!local_changes_->empty() && local_changes_->back().IsDelete())) { 352 sync_action_ = SYNC_ACTION_ADDED; 353 // Missing local file case. 354 // Download the file and add it to local as a new file. 355 DownloadFile(callback); 356 return; 357 } 358 359 DCHECK(local_changes_->empty() || local_changes_->back().IsAddOrUpdate()); 360 if (local_changes_->empty()) { 361 if (local_metadata_->file_type == SYNC_FILE_TYPE_FILE) { 362 sync_action_ = SYNC_ACTION_UPDATED; 363 // Download the file and overwrite the existing local file. 364 DownloadFile(callback); 365 return; 366 } 367 368 DCHECK_EQ(SYNC_FILE_TYPE_DIRECTORY, local_metadata_->file_type); 369 370 // Got a remote regular file modification for existing local folder. 371 // Our policy prioritize folders in this case. 372 // Lower the priority of the tracker to prevent repeated remote sync to the 373 // same tracker, and let local-to-remote sync phase process this change. 374 metadata_database()->LowerTrackerPriority(dirty_tracker_->tracker_id()); 375 remote_change_processor()->RecordFakeLocalChange( 376 url_, 377 FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE, 378 local_metadata_->file_type), 379 callback); 380 return; 381 } 382 383 DCHECK(local_changes_->back().IsAddOrUpdate()); 384 // Conflict case. 385 // Do nothing for the change now, and handle this in LocalToRemoteSync phase. 386 387 // Lower the priority of the tracker to prevent repeated remote sync to the 388 // same tracker. 389 metadata_database()->LowerTrackerPriority(dirty_tracker_->tracker_id()); 390 callback.Run(SYNC_STATUS_RETRY); 391} 392 393void RemoteToLocalSyncer::HandleFolderUpdate( 394 const SyncStatusCallback& callback) { 395 DCHECK(dirty_tracker_); 396 DCHECK(dirty_tracker_->active()); 397 DCHECK(!HasDisabledAppRoot(metadata_database(), *dirty_tracker_)); 398 399 DCHECK(remote_metadata_); 400 DCHECK(remote_metadata_->has_details()); 401 DCHECK(!remote_metadata_->details().missing()); 402 DCHECK_EQ(FILE_KIND_FOLDER, remote_metadata_->details().file_kind()); 403 404 Prepare(base::Bind(&RemoteToLocalSyncer::DidPrepareForFolderUpdate, 405 weak_ptr_factory_.GetWeakPtr(), callback)); 406} 407 408void RemoteToLocalSyncer::DidPrepareForFolderUpdate( 409 const SyncStatusCallback& callback, 410 SyncStatusCode status) { 411 if (status != SYNC_STATUS_OK) { 412 callback.Run(status); 413 return; 414 } 415 416 DCHECK(url_.is_valid()); 417 DCHECK(local_metadata_); 418 DCHECK(local_changes_); 419 420 // Check if the local file exists. 421 if (local_metadata_->file_type == SYNC_FILE_TYPE_UNKNOWN || 422 (!local_changes_->empty() && local_changes_->back().IsDelete())) { 423 sync_action_ = SYNC_ACTION_ADDED; 424 // No local file exists at the path. 425 CreateFolder(callback); 426 return; 427 } 428 429 if (local_metadata_->file_type == SYNC_FILE_TYPE_DIRECTORY) { 430 // There already exists a folder, nothing left to do. 431 if (dirty_tracker_->needs_folder_listing() && 432 !dirty_tracker_->synced_details().missing()) { 433 ListFolderContent(callback); 434 } else { 435 callback.Run(SYNC_STATUS_OK); 436 } 437 return; 438 } 439 440 DCHECK_EQ(SYNC_FILE_TYPE_FILE, local_metadata_->file_type); 441 sync_action_ = SYNC_ACTION_ADDED; 442 // Got a remote folder for existing local file. 443 // Our policy prioritize folders in this case. 444 CreateFolder(callback); 445} 446 447void RemoteToLocalSyncer::HandleSyncRootDeletion( 448 const SyncStatusCallback& callback) { 449 sync_root_deletion_ = true; 450 callback.Run(SYNC_STATUS_OK); 451} 452 453void RemoteToLocalSyncer::HandleDeletion( 454 const SyncStatusCallback& callback) { 455 DCHECK(dirty_tracker_); 456 DCHECK(dirty_tracker_->active()); 457 DCHECK(!HasDisabledAppRoot(metadata_database(), *dirty_tracker_)); 458 DCHECK(dirty_tracker_->has_synced_details()); 459 DCHECK(!dirty_tracker_->synced_details().missing()); 460 461 DCHECK(remote_metadata_); 462 DCHECK(remote_metadata_->has_details()); 463 DCHECK(remote_metadata_->details().missing()); 464 465 Prepare(base::Bind(&RemoteToLocalSyncer::DidPrepareForDeletion, 466 weak_ptr_factory_.GetWeakPtr(), callback)); 467} 468 469void RemoteToLocalSyncer::DidPrepareForDeletion( 470 const SyncStatusCallback& callback, 471 SyncStatusCode status) { 472 if (status != SYNC_STATUS_OK) { 473 callback.Run(status); 474 return; 475 } 476 477 DCHECK(url_.is_valid()); 478 DCHECK(local_metadata_); 479 DCHECK(local_changes_); 480 481 // Check if the local file exists. 482 if (local_metadata_->file_type == SYNC_FILE_TYPE_UNKNOWN || 483 (!local_changes_->empty() && local_changes_->back().IsDelete())) { 484 // No local file exists at the path. 485 callback.Run(SYNC_STATUS_OK); 486 return; 487 } 488 489 DCHECK(local_changes_->empty() || local_changes_->back().IsAddOrUpdate()); 490 if (local_changes_->empty()) { 491 sync_action_ = SYNC_ACTION_DELETED; 492 DeleteLocalFile(callback); 493 return; 494 } 495 496 DCHECK(local_changes_->back().IsAddOrUpdate()); 497 // File is remotely deleted and locally updated. 498 // Ignore the remote deletion and handle it as if applied successfully. 499 callback.Run(SYNC_STATUS_OK); 500} 501 502void RemoteToLocalSyncer::HandleContentUpdate( 503 const SyncStatusCallback& callback) { 504 DCHECK(dirty_tracker_); 505 DCHECK(dirty_tracker_->active()); 506 DCHECK(!HasDisabledAppRoot(metadata_database(), *dirty_tracker_)); 507 DCHECK(dirty_tracker_->has_synced_details()); 508 DCHECK_EQ(FILE_KIND_FILE, dirty_tracker_->synced_details().file_kind()); 509 510 DCHECK(remote_metadata_); 511 DCHECK(remote_metadata_->has_details()); 512 DCHECK(!remote_metadata_->details().missing()); 513 514 DCHECK_NE(dirty_tracker_->synced_details().md5(), 515 remote_metadata_->details().md5()); 516 517 Prepare(base::Bind(&RemoteToLocalSyncer::DidPrepareForAddOrUpdateFile, 518 weak_ptr_factory_.GetWeakPtr(), callback)); 519} 520 521void RemoteToLocalSyncer::ListFolderContent( 522 const SyncStatusCallback& callback) { 523 DCHECK(dirty_tracker_); 524 DCHECK(dirty_tracker_->active()); 525 DCHECK(!HasDisabledAppRoot(metadata_database(), *dirty_tracker_)); 526 DCHECK(dirty_tracker_->has_synced_details()); 527 DCHECK(!dirty_tracker_->synced_details().missing()); 528 DCHECK_EQ(FILE_KIND_FOLDER, dirty_tracker_->synced_details().file_kind()); 529 DCHECK(dirty_tracker_->needs_folder_listing()); 530 531 DCHECK(remote_metadata_); 532 DCHECK(remote_metadata_->has_details()); 533 DCHECK(!remote_metadata_->details().missing()); 534 535 // TODO(tzik): Replace this call with ChildList version. 536 drive_service()->GetFileListInDirectory( 537 dirty_tracker_->file_id(), 538 base::Bind(&RemoteToLocalSyncer::DidListFolderContent, 539 weak_ptr_factory_.GetWeakPtr(), 540 callback, 541 base::Passed(make_scoped_ptr(new FileIDList)))); 542} 543 544void RemoteToLocalSyncer::DidListFolderContent( 545 const SyncStatusCallback& callback, 546 scoped_ptr<FileIDList> children, 547 google_apis::GDataErrorCode error, 548 scoped_ptr<google_apis::FileList> file_list) { 549 SyncStatusCode status = GDataErrorCodeToSyncStatusCode(error); 550 if (status != SYNC_STATUS_OK) { 551 callback.Run(status); 552 return; 553 } 554 555 if (!file_list) { 556 NOTREACHED(); 557 callback.Run(SYNC_STATUS_FAILED); 558 return; 559 } 560 561 children->reserve(children->size() + file_list->items().size()); 562 for (ScopedVector<google_apis::FileResource>::const_iterator itr = 563 file_list->items().begin(); 564 itr != file_list->items().end(); 565 ++itr) { 566 children->push_back((*itr)->file_id()); 567 } 568 569 if (!file_list->next_link().is_empty()) { 570 drive_service()->GetRemainingFileList( 571 file_list->next_link(), 572 base::Bind(&RemoteToLocalSyncer::DidListFolderContent, 573 weak_ptr_factory_.GetWeakPtr(), 574 callback, base::Passed(&children))); 575 return; 576 } 577 578 metadata_database()->PopulateFolderByChildList( 579 dirty_tracker_->file_id(), *children, callback); 580} 581 582void RemoteToLocalSyncer::SyncCompleted(const SyncStatusCallback& callback, 583 SyncStatusCode status) { 584 util::Log(logging::LOG_VERBOSE, FROM_HERE, 585 "[Remote -> Local]: Finished: action=%s, tracker=%" PRId64 586 " status=%s", 587 SyncActionToString(sync_action_), dirty_tracker_->tracker_id(), 588 SyncStatusCodeToString(status)); 589 590 if (sync_root_deletion_) { 591 callback.Run(SYNC_STATUS_OK); 592 return; 593 } 594 595 if (status == SYNC_STATUS_RETRY) { 596 callback.Run(SYNC_STATUS_OK); 597 return; 598 } 599 600 if (status != SYNC_STATUS_OK) { 601 callback.Run(status); 602 return; 603 } 604 605 DCHECK(dirty_tracker_); 606 DCHECK(remote_metadata_); 607 DCHECK(remote_metadata_->has_details()); 608 609 FileDetails updated_details = remote_metadata_->details(); 610 if (!dirty_tracker_->active() || 611 HasDisabledAppRoot(metadata_database(), *dirty_tracker_)) { 612 // Operations for an inactive tracker don't update file content. 613 if (dirty_tracker_->has_synced_details()) 614 updated_details.set_md5(dirty_tracker_->synced_details().md5()); 615 if (!dirty_tracker_->active()) { 616 // Keep missing true, as the change hasn't been synced to local. 617 updated_details.clear_md5(); 618 updated_details.set_missing(true); 619 } 620 } 621 metadata_database()->UpdateTracker(dirty_tracker_->tracker_id(), 622 updated_details, 623 callback); 624} 625 626void RemoteToLocalSyncer::FinalizeSync(const SyncStatusCallback& callback, 627 SyncStatusCode status) { 628 if (prepared_) { 629 remote_change_processor()->FinalizeRemoteSync( 630 url_, false /* clear_local_change */, base::Bind(callback, status)); 631 return; 632 } 633 634 callback.Run(status); 635} 636 637void RemoteToLocalSyncer::Prepare(const SyncStatusCallback& callback) { 638 bool should_success = BuildFileSystemURL( 639 metadata_database(), *dirty_tracker_, &url_); 640 DCHECK(should_success); 641 DCHECK(url_.is_valid()); 642 remote_change_processor()->PrepareForProcessRemoteChange( 643 url_, 644 base::Bind(&RemoteToLocalSyncer::DidPrepare, 645 weak_ptr_factory_.GetWeakPtr(), 646 callback)); 647} 648 649void RemoteToLocalSyncer::DidPrepare(const SyncStatusCallback& callback, 650 SyncStatusCode status, 651 const SyncFileMetadata& local_metadata, 652 const FileChangeList& local_changes) { 653 if (status != SYNC_STATUS_OK) { 654 callback.Run(status); 655 return; 656 } 657 prepared_ = true; 658 659 local_metadata_.reset(new SyncFileMetadata(local_metadata)); 660 local_changes_.reset(new FileChangeList(local_changes)); 661 662 callback.Run(status); 663} 664 665void RemoteToLocalSyncer::DeleteLocalFile(const SyncStatusCallback& callback) { 666 remote_change_processor()->ApplyRemoteChange( 667 FileChange(FileChange::FILE_CHANGE_DELETE, SYNC_FILE_TYPE_UNKNOWN), 668 base::FilePath(), 669 url_, 670 callback); 671} 672 673void RemoteToLocalSyncer::DownloadFile(const SyncStatusCallback& callback) { 674 base::PostTaskAndReplyWithResult( 675 sync_context_->GetFileTaskRunner(), FROM_HERE, 676 base::Bind(&sync_file_system::drive_backend::CreateTemporaryFile, 677 make_scoped_refptr(sync_context_->GetFileTaskRunner())), 678 base::Bind(&RemoteToLocalSyncer::DidCreateTemporaryFileForDownload, 679 weak_ptr_factory_.GetWeakPtr(), callback)); 680} 681 682void RemoteToLocalSyncer::DidCreateTemporaryFileForDownload( 683 const SyncStatusCallback& callback, 684 webkit_blob::ScopedFile file) { 685 base::FilePath path = file.path(); 686 drive_service()->DownloadFile( 687 path, remote_metadata_->file_id(), 688 base::Bind(&RemoteToLocalSyncer::DidDownloadFile, 689 weak_ptr_factory_.GetWeakPtr(), 690 callback, base::Passed(&file)), 691 google_apis::GetContentCallback(), 692 google_apis::ProgressCallback()); 693} 694 695void RemoteToLocalSyncer::DidDownloadFile(const SyncStatusCallback& callback, 696 webkit_blob::ScopedFile file, 697 google_apis::GDataErrorCode error, 698 const base::FilePath&) { 699 SyncStatusCode status = GDataErrorCodeToSyncStatusCode(error); 700 if (status != SYNC_STATUS_OK) { 701 callback.Run(status); 702 return; 703 } 704 705 base::FilePath path = file.path(); 706 base::PostTaskAndReplyWithResult( 707 sync_context_->GetFileTaskRunner(), FROM_HERE, 708 base::Bind(&drive::util::GetMd5Digest, path), 709 base::Bind(&RemoteToLocalSyncer::DidCalculateMD5ForDownload, 710 weak_ptr_factory_.GetWeakPtr(), 711 callback, base::Passed(&file))); 712} 713 714void RemoteToLocalSyncer::DidCalculateMD5ForDownload( 715 const SyncStatusCallback& callback, 716 webkit_blob::ScopedFile file, 717 const std::string& md5) { 718 if (md5.empty()) { 719 callback.Run(SYNC_FILE_ERROR_NOT_FOUND); 720 return; 721 } 722 723 if (md5 != remote_metadata_->details().md5()) { 724 // File has been modified since last metadata retrieval. 725 726 // Lower the priority of the tracker to prevent repeated remote sync to the 727 // same tracker. 728 metadata_database()->LowerTrackerPriority(dirty_tracker_->tracker_id()); 729 callback.Run(SYNC_STATUS_RETRY); 730 return; 731 } 732 733 base::FilePath path = file.path(); 734 remote_change_processor()->ApplyRemoteChange( 735 FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE, SYNC_FILE_TYPE_FILE), 736 path, url_, 737 base::Bind(&RemoteToLocalSyncer::DidApplyDownload, 738 weak_ptr_factory_.GetWeakPtr(), 739 callback, base::Passed(&file))); 740} 741 742void RemoteToLocalSyncer::DidApplyDownload(const SyncStatusCallback& callback, 743 webkit_blob::ScopedFile, 744 SyncStatusCode status) { 745 if (status != SYNC_STATUS_OK) 746 metadata_database()->LowerTrackerPriority(dirty_tracker_->tracker_id()); 747 callback.Run(status); 748} 749 750void RemoteToLocalSyncer::CreateFolder(const SyncStatusCallback& callback) { 751 remote_change_processor()->ApplyRemoteChange( 752 FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE, 753 SYNC_FILE_TYPE_DIRECTORY), 754 base::FilePath(), url_, 755 callback); 756} 757 758drive::DriveServiceInterface* RemoteToLocalSyncer::drive_service() { 759 return sync_context_->GetDriveService(); 760} 761 762MetadataDatabase* RemoteToLocalSyncer::metadata_database() { 763 return sync_context_->GetMetadataDatabase(); 764} 765 766RemoteChangeProcessor* RemoteToLocalSyncer::remote_change_processor() { 767 DCHECK(sync_context_->GetRemoteChangeProcessor()); 768 return sync_context_->GetRemoteChangeProcessor(); 769} 770 771} // namespace drive_backend 772} // namespace sync_file_system 773