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