remote_to_local_syncer.cc revision cedac228d2dd51db4b79ea1e72c7f249408ee061
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()->GetResourceEntry( 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::ResourceEntry> entry) { 299 SyncStatusCode status = GDataErrorCodeToSyncStatusCode(error); 300 if (status != SYNC_STATUS_OK && 301 error != google_apis::HTTP_NOT_FOUND) { 302 callback.Run(status); 303 return; 304 } 305 306 if (error == google_apis::HTTP_NOT_FOUND) { 307 metadata_database()->UpdateByDeletedRemoteFile( 308 dirty_tracker_->file_id(), callback); 309 return; 310 } 311 312 if (!entry) { 313 NOTREACHED(); 314 callback.Run(SYNC_STATUS_FAILED); 315 return; 316 } 317 318 metadata_database()->UpdateByFileResource( 319 *drive::util::ConvertResourceEntryToFileResource(*entry), 320 base::Bind(&RemoteToLocalSyncer::DidUpdateDatabaseForRemoteMetadata, 321 weak_ptr_factory_.GetWeakPtr(), callback)); 322} 323 324void RemoteToLocalSyncer::DidUpdateDatabaseForRemoteMetadata( 325 const SyncStatusCallback& callback, 326 SyncStatusCode status) { 327 if (status != SYNC_STATUS_OK) { 328 callback.Run(status); 329 return; 330 } 331 332 callback.Run(SYNC_STATUS_RETRY); // Do not update |dirty_tracker_|. 333} 334 335void RemoteToLocalSyncer::DidPrepareForAddOrUpdateFile( 336 const SyncStatusCallback& callback, 337 SyncStatusCode status) { 338 if (status != SYNC_STATUS_OK) { 339 callback.Run(status); 340 return; 341 } 342 343 DCHECK(url_.is_valid()); 344 DCHECK(local_metadata_); 345 DCHECK(local_changes_); 346 347 // Check if the local file exists. 348 if (local_metadata_->file_type == SYNC_FILE_TYPE_UNKNOWN || 349 (!local_changes_->empty() && local_changes_->back().IsDelete())) { 350 sync_action_ = SYNC_ACTION_ADDED; 351 // Missing local file case. 352 // Download the file and add it to local as a new file. 353 DownloadFile(callback); 354 return; 355 } 356 357 DCHECK(local_changes_->empty() || local_changes_->back().IsAddOrUpdate()); 358 if (local_changes_->empty()) { 359 if (local_metadata_->file_type == SYNC_FILE_TYPE_FILE) { 360 sync_action_ = SYNC_ACTION_UPDATED; 361 // Download the file and overwrite the existing local file. 362 DownloadFile(callback); 363 return; 364 } 365 366 DCHECK_EQ(SYNC_FILE_TYPE_DIRECTORY, local_metadata_->file_type); 367 368 // Got a remote regular file modification for existing local folder. 369 // Our policy prioritize folders in this case. 370 // Lower the priority of the tracker to prevent repeated remote sync to the 371 // same tracker, and let local-to-remote sync phase process this change. 372 metadata_database()->LowerTrackerPriority(dirty_tracker_->tracker_id()); 373 remote_change_processor()->RecordFakeLocalChange( 374 url_, 375 FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE, 376 local_metadata_->file_type), 377 callback); 378 return; 379 } 380 381 DCHECK(local_changes_->back().IsAddOrUpdate()); 382 // Conflict case. 383 // Do nothing for the change now, and handle this in LocalToRemoteSync phase. 384 385 // Lower the priority of the tracker to prevent repeated remote sync to the 386 // same tracker. 387 metadata_database()->LowerTrackerPriority(dirty_tracker_->tracker_id()); 388 callback.Run(SYNC_STATUS_RETRY); 389} 390 391void RemoteToLocalSyncer::HandleFolderUpdate( 392 const SyncStatusCallback& callback) { 393 DCHECK(dirty_tracker_); 394 DCHECK(dirty_tracker_->active()); 395 DCHECK(!HasDisabledAppRoot(metadata_database(), *dirty_tracker_)); 396 397 DCHECK(remote_metadata_); 398 DCHECK(remote_metadata_->has_details()); 399 DCHECK(!remote_metadata_->details().missing()); 400 DCHECK_EQ(FILE_KIND_FOLDER, remote_metadata_->details().file_kind()); 401 402 Prepare(base::Bind(&RemoteToLocalSyncer::DidPrepareForFolderUpdate, 403 weak_ptr_factory_.GetWeakPtr(), callback)); 404} 405 406void RemoteToLocalSyncer::DidPrepareForFolderUpdate( 407 const SyncStatusCallback& callback, 408 SyncStatusCode status) { 409 if (status != SYNC_STATUS_OK) { 410 callback.Run(status); 411 return; 412 } 413 414 DCHECK(url_.is_valid()); 415 DCHECK(local_metadata_); 416 DCHECK(local_changes_); 417 418 // Check if the local file exists. 419 if (local_metadata_->file_type == SYNC_FILE_TYPE_UNKNOWN || 420 (!local_changes_->empty() && local_changes_->back().IsDelete())) { 421 sync_action_ = SYNC_ACTION_ADDED; 422 // No local file exists at the path. 423 CreateFolder(callback); 424 return; 425 } 426 427 if (local_metadata_->file_type == SYNC_FILE_TYPE_DIRECTORY) { 428 // There already exists a folder, nothing left to do. 429 if (dirty_tracker_->needs_folder_listing() && 430 !dirty_tracker_->synced_details().missing()) { 431 ListFolderContent(callback); 432 } else { 433 callback.Run(SYNC_STATUS_OK); 434 } 435 return; 436 } 437 438 DCHECK_EQ(SYNC_FILE_TYPE_FILE, local_metadata_->file_type); 439 sync_action_ = SYNC_ACTION_ADDED; 440 // Got a remote folder for existing local file. 441 // Our policy prioritize folders in this case. 442 CreateFolder(callback); 443} 444 445void RemoteToLocalSyncer::HandleSyncRootDeletion( 446 const SyncStatusCallback& callback) { 447 sync_root_deletion_ = true; 448 callback.Run(SYNC_STATUS_OK); 449} 450 451void RemoteToLocalSyncer::HandleDeletion( 452 const SyncStatusCallback& callback) { 453 DCHECK(dirty_tracker_); 454 DCHECK(dirty_tracker_->active()); 455 DCHECK(!HasDisabledAppRoot(metadata_database(), *dirty_tracker_)); 456 DCHECK(dirty_tracker_->has_synced_details()); 457 DCHECK(!dirty_tracker_->synced_details().missing()); 458 459 DCHECK(remote_metadata_); 460 DCHECK(remote_metadata_->has_details()); 461 DCHECK(remote_metadata_->details().missing()); 462 463 Prepare(base::Bind(&RemoteToLocalSyncer::DidPrepareForDeletion, 464 weak_ptr_factory_.GetWeakPtr(), callback)); 465} 466 467void RemoteToLocalSyncer::DidPrepareForDeletion( 468 const SyncStatusCallback& callback, 469 SyncStatusCode status) { 470 if (status != SYNC_STATUS_OK) { 471 callback.Run(status); 472 return; 473 } 474 475 DCHECK(url_.is_valid()); 476 DCHECK(local_metadata_); 477 DCHECK(local_changes_); 478 479 // Check if the local file exists. 480 if (local_metadata_->file_type == SYNC_FILE_TYPE_UNKNOWN || 481 (!local_changes_->empty() && local_changes_->back().IsDelete())) { 482 // No local file exists at the path. 483 callback.Run(SYNC_STATUS_OK); 484 return; 485 } 486 487 DCHECK(local_changes_->empty() || local_changes_->back().IsAddOrUpdate()); 488 if (local_changes_->empty()) { 489 sync_action_ = SYNC_ACTION_DELETED; 490 DeleteLocalFile(callback); 491 return; 492 } 493 494 DCHECK(local_changes_->back().IsAddOrUpdate()); 495 // File is remotely deleted and locally updated. 496 // Ignore the remote deletion and handle it as if applied successfully. 497 callback.Run(SYNC_STATUS_OK); 498} 499 500void RemoteToLocalSyncer::HandleContentUpdate( 501 const SyncStatusCallback& callback) { 502 DCHECK(dirty_tracker_); 503 DCHECK(dirty_tracker_->active()); 504 DCHECK(!HasDisabledAppRoot(metadata_database(), *dirty_tracker_)); 505 DCHECK(dirty_tracker_->has_synced_details()); 506 DCHECK_EQ(FILE_KIND_FILE, dirty_tracker_->synced_details().file_kind()); 507 508 DCHECK(remote_metadata_); 509 DCHECK(remote_metadata_->has_details()); 510 DCHECK(!remote_metadata_->details().missing()); 511 512 DCHECK_NE(dirty_tracker_->synced_details().md5(), 513 remote_metadata_->details().md5()); 514 515 Prepare(base::Bind(&RemoteToLocalSyncer::DidPrepareForAddOrUpdateFile, 516 weak_ptr_factory_.GetWeakPtr(), callback)); 517} 518 519void RemoteToLocalSyncer::ListFolderContent( 520 const SyncStatusCallback& callback) { 521 DCHECK(dirty_tracker_); 522 DCHECK(dirty_tracker_->active()); 523 DCHECK(!HasDisabledAppRoot(metadata_database(), *dirty_tracker_)); 524 DCHECK(dirty_tracker_->has_synced_details()); 525 DCHECK(!dirty_tracker_->synced_details().missing()); 526 DCHECK_EQ(FILE_KIND_FOLDER, dirty_tracker_->synced_details().file_kind()); 527 DCHECK(dirty_tracker_->needs_folder_listing()); 528 529 DCHECK(remote_metadata_); 530 DCHECK(remote_metadata_->has_details()); 531 DCHECK(!remote_metadata_->details().missing()); 532 533 // TODO(tzik): Replace this call with ChildList version. 534 drive_service()->GetResourceListInDirectory( 535 dirty_tracker_->file_id(), 536 base::Bind(&RemoteToLocalSyncer::DidListFolderContent, 537 weak_ptr_factory_.GetWeakPtr(), 538 callback, 539 base::Passed(make_scoped_ptr(new FileIDList)))); 540} 541 542void RemoteToLocalSyncer::DidListFolderContent( 543 const SyncStatusCallback& callback, 544 scoped_ptr<FileIDList> children, 545 google_apis::GDataErrorCode error, 546 scoped_ptr<google_apis::ResourceList> resource_list) { 547 SyncStatusCode status = GDataErrorCodeToSyncStatusCode(error); 548 if (status != SYNC_STATUS_OK) { 549 callback.Run(status); 550 return; 551 } 552 553 if (!resource_list) { 554 NOTREACHED(); 555 callback.Run(SYNC_STATUS_FAILED); 556 return; 557 } 558 559 children->reserve(children->size() + resource_list->entries().size()); 560 for (ScopedVector<google_apis::ResourceEntry>::const_iterator itr = 561 resource_list->entries().begin(); 562 itr != resource_list->entries().end(); 563 ++itr) { 564 children->push_back((*itr)->resource_id()); 565 } 566 567 GURL next_feed; 568 if (resource_list->GetNextFeedURL(&next_feed)) { 569 drive_service()->GetRemainingFileList( 570 next_feed, 571 base::Bind(&RemoteToLocalSyncer::DidListFolderContent, 572 weak_ptr_factory_.GetWeakPtr(), 573 callback, base::Passed(&children))); 574 return; 575 } 576 577 metadata_database()->PopulateFolderByChildList( 578 dirty_tracker_->file_id(), *children, callback); 579} 580 581void RemoteToLocalSyncer::SyncCompleted(const SyncStatusCallback& callback, 582 SyncStatusCode status) { 583 util::Log(logging::LOG_VERBOSE, FROM_HERE, 584 "[Remote -> Local]: Finished: action=%s, tracker=%" PRId64 585 " status=%s", 586 SyncActionToString(sync_action_), dirty_tracker_->tracker_id(), 587 SyncStatusCodeToString(status)); 588 589 if (sync_root_deletion_) { 590 callback.Run(SYNC_STATUS_OK); 591 return; 592 } 593 594 if (status == SYNC_STATUS_RETRY) { 595 callback.Run(SYNC_STATUS_OK); 596 return; 597 } 598 599 if (status != SYNC_STATUS_OK) { 600 callback.Run(status); 601 return; 602 } 603 604 DCHECK(dirty_tracker_); 605 DCHECK(remote_metadata_); 606 DCHECK(remote_metadata_->has_details()); 607 608 FileDetails updated_details = remote_metadata_->details(); 609 if (!dirty_tracker_->active() || 610 HasDisabledAppRoot(metadata_database(), *dirty_tracker_)) { 611 // Operations for an inactive tracker don't update file content. 612 if (dirty_tracker_->has_synced_details()) 613 updated_details.set_md5(dirty_tracker_->synced_details().md5()); 614 if (!dirty_tracker_->active()) { 615 // Keep missing true, as the change hasn't been synced to local. 616 updated_details.clear_md5(); 617 updated_details.set_missing(true); 618 } 619 } 620 metadata_database()->UpdateTracker(dirty_tracker_->tracker_id(), 621 updated_details, 622 callback); 623} 624 625void RemoteToLocalSyncer::FinalizeSync(const SyncStatusCallback& callback, 626 SyncStatusCode status) { 627 if (prepared_) { 628 remote_change_processor()->FinalizeRemoteSync( 629 url_, false /* clear_local_change */, base::Bind(callback, status)); 630 return; 631 } 632 633 callback.Run(status); 634} 635 636void RemoteToLocalSyncer::Prepare(const SyncStatusCallback& callback) { 637 bool should_success = BuildFileSystemURL( 638 metadata_database(), *dirty_tracker_, &url_); 639 DCHECK(should_success); 640 DCHECK(url_.is_valid()); 641 remote_change_processor()->PrepareForProcessRemoteChange( 642 url_, 643 base::Bind(&RemoteToLocalSyncer::DidPrepare, 644 weak_ptr_factory_.GetWeakPtr(), 645 callback)); 646} 647 648void RemoteToLocalSyncer::DidPrepare(const SyncStatusCallback& callback, 649 SyncStatusCode status, 650 const SyncFileMetadata& local_metadata, 651 const FileChangeList& local_changes) { 652 if (status != SYNC_STATUS_OK) { 653 callback.Run(status); 654 return; 655 } 656 prepared_ = true; 657 658 local_metadata_.reset(new SyncFileMetadata(local_metadata)); 659 local_changes_.reset(new FileChangeList(local_changes)); 660 661 callback.Run(status); 662} 663 664void RemoteToLocalSyncer::DeleteLocalFile(const SyncStatusCallback& callback) { 665 remote_change_processor()->ApplyRemoteChange( 666 FileChange(FileChange::FILE_CHANGE_DELETE, SYNC_FILE_TYPE_UNKNOWN), 667 base::FilePath(), 668 url_, 669 callback); 670} 671 672void RemoteToLocalSyncer::DownloadFile(const SyncStatusCallback& callback) { 673 base::PostTaskAndReplyWithResult( 674 sync_context_->GetFileTaskRunner(), FROM_HERE, 675 base::Bind(&sync_file_system::drive_backend::CreateTemporaryFile, 676 make_scoped_refptr(sync_context_->GetFileTaskRunner())), 677 base::Bind(&RemoteToLocalSyncer::DidCreateTemporaryFileForDownload, 678 weak_ptr_factory_.GetWeakPtr(), callback)); 679} 680 681void RemoteToLocalSyncer::DidCreateTemporaryFileForDownload( 682 const SyncStatusCallback& callback, 683 webkit_blob::ScopedFile file) { 684 base::FilePath path = file.path(); 685 drive_service()->DownloadFile( 686 path, remote_metadata_->file_id(), 687 base::Bind(&RemoteToLocalSyncer::DidDownloadFile, 688 weak_ptr_factory_.GetWeakPtr(), 689 callback, base::Passed(&file)), 690 google_apis::GetContentCallback(), 691 google_apis::ProgressCallback()); 692} 693 694void RemoteToLocalSyncer::DidDownloadFile(const SyncStatusCallback& callback, 695 webkit_blob::ScopedFile file, 696 google_apis::GDataErrorCode error, 697 const base::FilePath&) { 698 SyncStatusCode status = GDataErrorCodeToSyncStatusCode(error); 699 if (status != SYNC_STATUS_OK) { 700 callback.Run(status); 701 return; 702 } 703 704 base::FilePath path = file.path(); 705 base::PostTaskAndReplyWithResult( 706 sync_context_->GetFileTaskRunner(), FROM_HERE, 707 base::Bind(&drive::util::GetMd5Digest, path), 708 base::Bind(&RemoteToLocalSyncer::DidCalculateMD5ForDownload, 709 weak_ptr_factory_.GetWeakPtr(), 710 callback, base::Passed(&file))); 711} 712 713void RemoteToLocalSyncer::DidCalculateMD5ForDownload( 714 const SyncStatusCallback& callback, 715 webkit_blob::ScopedFile file, 716 const std::string& md5) { 717 if (md5.empty()) { 718 callback.Run(SYNC_FILE_ERROR_NOT_FOUND); 719 return; 720 } 721 722 if (md5 != remote_metadata_->details().md5()) { 723 // File has been modified since last metadata retrieval. 724 725 // Lower the priority of the tracker to prevent repeated remote sync to the 726 // same tracker. 727 metadata_database()->LowerTrackerPriority(dirty_tracker_->tracker_id()); 728 callback.Run(SYNC_STATUS_RETRY); 729 return; 730 } 731 732 base::FilePath path = file.path(); 733 remote_change_processor()->ApplyRemoteChange( 734 FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE, SYNC_FILE_TYPE_FILE), 735 path, url_, 736 base::Bind(&RemoteToLocalSyncer::DidApplyDownload, 737 weak_ptr_factory_.GetWeakPtr(), 738 callback, base::Passed(&file))); 739} 740 741void RemoteToLocalSyncer::DidApplyDownload(const SyncStatusCallback& callback, 742 webkit_blob::ScopedFile, 743 SyncStatusCode status) { 744 if (status != SYNC_STATUS_OK) 745 metadata_database()->LowerTrackerPriority(dirty_tracker_->tracker_id()); 746 callback.Run(status); 747} 748 749void RemoteToLocalSyncer::CreateFolder(const SyncStatusCallback& callback) { 750 remote_change_processor()->ApplyRemoteChange( 751 FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE, 752 SYNC_FILE_TYPE_DIRECTORY), 753 base::FilePath(), url_, 754 callback); 755} 756 757drive::DriveServiceInterface* RemoteToLocalSyncer::drive_service() { 758 return sync_context_->GetDriveService(); 759} 760 761MetadataDatabase* RemoteToLocalSyncer::metadata_database() { 762 return sync_context_->GetMetadataDatabase(); 763} 764 765RemoteChangeProcessor* RemoteToLocalSyncer::remote_change_processor() { 766 DCHECK(sync_context_->GetRemoteChangeProcessor()); 767 return sync_context_->GetRemoteChangeProcessor(); 768} 769 770} // namespace drive_backend 771} // namespace sync_file_system 772