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/drive_file_sync_service.h" 6 7 #include <algorithm> 8 #include <string> 9 #include <utility> 10 11 #include "base/bind.h" 12 #include "base/file_util.h" 13 #include "base/location.h" 14 #include "base/memory/weak_ptr.h" 15 #include "base/message_loop/message_loop_proxy.h" 16 #include "base/strings/utf_string_conversions.h" 17 #include "base/values.h" 18 #include "chrome/browser/drive/drive_api_util.h" 19 #include "chrome/browser/drive/drive_notification_manager.h" 20 #include "chrome/browser/drive/drive_notification_manager_factory.h" 21 #include "chrome/browser/extensions/extension_service.h" 22 #include "chrome/browser/extensions/extension_system.h" 23 #include "chrome/browser/profiles/profile.h" 24 #include "chrome/browser/sync_file_system/drive_backend/api_util.h" 25 #include "chrome/browser/sync_file_system/drive_backend/drive_file_sync_util.h" 26 #include "chrome/browser/sync_file_system/drive_backend/drive_metadata_store.h" 27 #include "chrome/browser/sync_file_system/drive_backend/local_sync_delegate.h" 28 #include "chrome/browser/sync_file_system/drive_backend/remote_sync_delegate.h" 29 #include "chrome/browser/sync_file_system/file_status_observer.h" 30 #include "chrome/browser/sync_file_system/logger.h" 31 #include "chrome/browser/sync_file_system/sync_file_metadata.h" 32 #include "chrome/browser/sync_file_system/sync_file_system.pb.h" 33 #include "chrome/browser/sync_file_system/sync_file_type.h" 34 #include "chrome/browser/sync_file_system/syncable_file_system_util.h" 35 #include "chrome/common/extensions/extension.h" 36 #include "content/public/browser/browser_thread.h" 37 #include "extensions/common/constants.h" 38 #include "webkit/browser/fileapi/file_system_url.h" 39 #include "webkit/common/blob/scoped_file.h" 40 #include "webkit/common/fileapi/file_system_util.h" 41 42 using fileapi::FileSystemURL; 43 44 namespace sync_file_system { 45 46 typedef RemoteFileSyncService::OriginStatusMap OriginStatusMap; 47 48 namespace { 49 50 const base::FilePath::CharType kTempDirName[] = FILE_PATH_LITERAL("tmp"); 51 const base::FilePath::CharType kSyncFileSystemDir[] = 52 FILE_PATH_LITERAL("Sync FileSystem"); 53 const base::FilePath::CharType kSyncFileSystemDirDev[] = 54 FILE_PATH_LITERAL("Sync FileSystem Dev"); 55 56 const base::FilePath::CharType* GetSyncFileSystemDir() { 57 return IsSyncFSDirectoryOperationEnabled() 58 ? kSyncFileSystemDirDev : kSyncFileSystemDir; 59 } 60 61 void EmptyStatusCallback(SyncStatusCode status) {} 62 63 } // namespace 64 65 ConflictResolutionPolicy DriveFileSyncService::kDefaultPolicy = 66 CONFLICT_RESOLUTION_POLICY_LAST_WRITE_WIN; 67 68 // DriveFileSyncService ------------------------------------------------------ 69 70 DriveFileSyncService::~DriveFileSyncService() { 71 if (api_util_) 72 api_util_->RemoveObserver(this); 73 74 drive::DriveNotificationManager* drive_notification_manager = 75 drive::DriveNotificationManagerFactory::GetForProfile(profile_); 76 if (drive_notification_manager) 77 drive_notification_manager->RemoveObserver(this); 78 } 79 80 scoped_ptr<DriveFileSyncService> DriveFileSyncService::Create( 81 Profile* profile) { 82 scoped_ptr<DriveFileSyncService> service(new DriveFileSyncService(profile)); 83 scoped_ptr<SyncTaskManager> task_manager( 84 new SyncTaskManager(service->AsWeakPtr())); 85 SyncStatusCallback callback = base::Bind( 86 &SyncTaskManager::Initialize, task_manager->AsWeakPtr()); 87 service->Initialize(task_manager.Pass(), callback); 88 return service.Pass(); 89 } 90 91 scoped_ptr<DriveFileSyncService> DriveFileSyncService::CreateForTesting( 92 Profile* profile, 93 const base::FilePath& base_dir, 94 scoped_ptr<drive_backend::APIUtilInterface> api_util, 95 scoped_ptr<DriveMetadataStore> metadata_store) { 96 scoped_ptr<DriveFileSyncService> service(new DriveFileSyncService(profile)); 97 scoped_ptr<SyncTaskManager> task_manager( 98 new SyncTaskManager(service->AsWeakPtr())); 99 SyncStatusCallback callback = base::Bind( 100 &SyncTaskManager::Initialize, task_manager->AsWeakPtr()); 101 service->InitializeForTesting(task_manager.Pass(), 102 base_dir, 103 api_util.Pass(), 104 metadata_store.Pass(), 105 callback); 106 return service.Pass(); 107 } 108 109 scoped_ptr<drive_backend::APIUtilInterface> 110 DriveFileSyncService::DestroyAndPassAPIUtilForTesting( 111 scoped_ptr<DriveFileSyncService> sync_service) { 112 return sync_service->api_util_.Pass(); 113 } 114 115 void DriveFileSyncService::AddServiceObserver(Observer* observer) { 116 service_observers_.AddObserver(observer); 117 } 118 119 void DriveFileSyncService::AddFileStatusObserver( 120 FileStatusObserver* observer) { 121 file_status_observers_.AddObserver(observer); 122 } 123 124 void DriveFileSyncService::RegisterOriginForTrackingChanges( 125 const GURL& origin, 126 const SyncStatusCallback& callback) { 127 task_manager_->ScheduleTask( 128 base::Bind(&DriveFileSyncService::DoRegisterOriginForTrackingChanges, 129 AsWeakPtr(), origin), 130 callback); 131 } 132 133 void DriveFileSyncService::UnregisterOriginForTrackingChanges( 134 const GURL& origin, 135 const SyncStatusCallback& callback) { 136 task_manager_->ScheduleTask( 137 base::Bind(&DriveFileSyncService::DoUnregisterOriginForTrackingChanges, 138 AsWeakPtr(), origin), 139 callback); 140 } 141 142 void DriveFileSyncService::EnableOriginForTrackingChanges( 143 const GURL& origin, 144 const SyncStatusCallback& callback) { 145 task_manager_->ScheduleTask( 146 base::Bind(&DriveFileSyncService::DoEnableOriginForTrackingChanges, 147 AsWeakPtr(), origin), 148 callback); 149 } 150 151 void DriveFileSyncService::DisableOriginForTrackingChanges( 152 const GURL& origin, 153 const SyncStatusCallback& callback) { 154 task_manager_->ScheduleTask( 155 base::Bind(&DriveFileSyncService::DoDisableOriginForTrackingChanges, 156 AsWeakPtr(), origin), 157 callback); 158 } 159 160 void DriveFileSyncService::UninstallOrigin( 161 const GURL& origin, 162 const SyncStatusCallback& callback) { 163 task_manager_->ScheduleTask( 164 base::Bind(&DriveFileSyncService::DoUninstallOrigin, AsWeakPtr(), origin), 165 callback); 166 } 167 168 void DriveFileSyncService::ProcessRemoteChange( 169 const SyncFileCallback& callback) { 170 task_manager_->ScheduleTask( 171 base::Bind(&DriveFileSyncService::DoProcessRemoteChange, AsWeakPtr(), 172 callback), 173 base::Bind(&EmptyStatusCallback)); 174 } 175 176 void DriveFileSyncService::SetRemoteChangeProcessor( 177 RemoteChangeProcessor* processor) { 178 remote_change_processor_ = processor; 179 } 180 181 LocalChangeProcessor* DriveFileSyncService::GetLocalChangeProcessor() { 182 return this; 183 } 184 185 bool DriveFileSyncService::IsConflicting(const FileSystemURL& url) { 186 DriveMetadata metadata; 187 const SyncStatusCode status = metadata_store_->ReadEntry(url, &metadata); 188 if (status != SYNC_STATUS_OK) { 189 DCHECK_EQ(SYNC_DATABASE_ERROR_NOT_FOUND, status); 190 return false; 191 } 192 return metadata.conflicted(); 193 } 194 195 RemoteServiceState DriveFileSyncService::GetCurrentState() const { 196 if (!sync_enabled_) 197 return REMOTE_SERVICE_DISABLED; 198 return state_; 199 } 200 201 void DriveFileSyncService::GetOriginStatusMap(OriginStatusMap* status_map) { 202 DCHECK(status_map); 203 204 // Add batch sync origins held by DriveFileSyncService. 205 typedef std::map<GURL, std::string>::const_iterator iterator; 206 for (iterator itr = pending_batch_sync_origins_.begin(); 207 itr != pending_batch_sync_origins_.end(); 208 ++itr) 209 (*status_map)[itr->first] = "Pending"; 210 211 // Add incremental and disabled origins held by DriveMetadataStore. 212 for (iterator itr = metadata_store_->incremental_sync_origins().begin(); 213 itr != metadata_store_->incremental_sync_origins().end(); 214 ++itr) 215 (*status_map)[itr->first] = "Enabled"; 216 217 for (iterator itr = metadata_store_->disabled_origins().begin(); 218 itr != metadata_store_->disabled_origins().end(); 219 ++itr) 220 (*status_map)[itr->first] = "Disabled"; 221 } 222 223 scoped_ptr<base::ListValue> DriveFileSyncService::DumpFiles( 224 const GURL& origin) { 225 return metadata_store_->DumpFiles(origin); 226 } 227 228 void DriveFileSyncService::SetSyncEnabled(bool enabled) { 229 if (sync_enabled_ == enabled) 230 return; 231 232 RemoteServiceState old_state = GetCurrentState(); 233 sync_enabled_ = enabled; 234 if (old_state == GetCurrentState()) 235 return; 236 237 const char* status_message = enabled ? "Sync is enabled" : "Sync is disabled"; 238 FOR_EACH_OBSERVER( 239 Observer, service_observers_, 240 OnRemoteServiceStateUpdated(GetCurrentState(), status_message)); 241 } 242 243 SyncStatusCode DriveFileSyncService::SetConflictResolutionPolicy( 244 ConflictResolutionPolicy policy) { 245 conflict_resolution_resolver_.set_policy(policy); 246 return SYNC_STATUS_OK; 247 } 248 249 ConflictResolutionPolicy 250 DriveFileSyncService::GetConflictResolutionPolicy() const { 251 return conflict_resolution_resolver_.policy(); 252 } 253 254 void DriveFileSyncService::ApplyLocalChange( 255 const FileChange& local_file_change, 256 const base::FilePath& local_file_path, 257 const SyncFileMetadata& local_file_metadata, 258 const FileSystemURL& url, 259 const SyncStatusCallback& callback) { 260 task_manager_->ScheduleTask( 261 base::Bind(&DriveFileSyncService::DoApplyLocalChange, AsWeakPtr(), 262 local_file_change, 263 local_file_path, 264 local_file_metadata, 265 url), 266 callback); 267 } 268 269 void DriveFileSyncService::OnAuthenticated() { 270 if (state_ == REMOTE_SERVICE_OK) 271 return; 272 util::Log(logging::LOG_INFO, FROM_HERE, "OnAuthenticated"); 273 274 UpdateServiceState(REMOTE_SERVICE_OK, "Authenticated"); 275 276 may_have_unfetched_changes_ = true; 277 MaybeStartFetchChanges(); 278 } 279 280 void DriveFileSyncService::OnNetworkConnected() { 281 if (state_ == REMOTE_SERVICE_OK) 282 return; 283 util::Log(logging::LOG_INFO, FROM_HERE, "OnNetworkConnected"); 284 285 UpdateServiceState(REMOTE_SERVICE_OK, "Network connected"); 286 287 may_have_unfetched_changes_ = true; 288 MaybeStartFetchChanges(); 289 } 290 291 DriveFileSyncService::DriveFileSyncService(Profile* profile) 292 : profile_(profile), 293 state_(REMOTE_SERVICE_OK), 294 sync_enabled_(true), 295 largest_fetched_changestamp_(0), 296 may_have_unfetched_changes_(false), 297 remote_change_processor_(NULL), 298 last_gdata_error_(google_apis::HTTP_SUCCESS), 299 conflict_resolution_resolver_(kDefaultPolicy) { 300 } 301 302 void DriveFileSyncService::Initialize( 303 scoped_ptr<SyncTaskManager> task_manager, 304 const SyncStatusCallback& callback) { 305 DCHECK(profile_); 306 DCHECK(!metadata_store_); 307 DCHECK(!task_manager_); 308 309 task_manager_ = task_manager.Pass(); 310 311 temporary_file_dir_ = 312 profile_->GetPath().Append(GetSyncFileSystemDir()).Append(kTempDirName); 313 314 api_util_.reset(new drive_backend::APIUtil(profile_, temporary_file_dir_)); 315 api_util_->AddObserver(this); 316 317 metadata_store_.reset(new DriveMetadataStore( 318 profile_->GetPath().Append(GetSyncFileSystemDir()), 319 content::BrowserThread::GetMessageLoopProxyForThread( 320 content::BrowserThread::FILE).get())); 321 322 metadata_store_->Initialize( 323 base::Bind(&DriveFileSyncService::DidInitializeMetadataStore, 324 AsWeakPtr(), callback)); 325 } 326 327 void DriveFileSyncService::InitializeForTesting( 328 scoped_ptr<SyncTaskManager> task_manager, 329 const base::FilePath& base_dir, 330 scoped_ptr<drive_backend::APIUtilInterface> api_util, 331 scoped_ptr<DriveMetadataStore> metadata_store, 332 const SyncStatusCallback& callback) { 333 DCHECK(!metadata_store_); 334 DCHECK(!task_manager_); 335 336 task_manager_ = task_manager.Pass(); 337 temporary_file_dir_ = base_dir.Append(kTempDirName); 338 339 api_util_ = api_util.Pass(); 340 metadata_store_ = metadata_store.Pass(); 341 342 base::MessageLoopProxy::current()->PostTask( 343 FROM_HERE, 344 base::Bind(&DriveFileSyncService::DidInitializeMetadataStore, 345 AsWeakPtr(), callback, SYNC_STATUS_OK, false)); 346 } 347 348 void DriveFileSyncService::DidInitializeMetadataStore( 349 const SyncStatusCallback& callback, 350 SyncStatusCode status, 351 bool created) { 352 if (status != SYNC_STATUS_OK) { 353 callback.Run(status); 354 return; 355 } 356 357 DCHECK(pending_batch_sync_origins_.empty()); 358 359 UpdateRegisteredOrigins(); 360 361 largest_fetched_changestamp_ = metadata_store_->GetLargestChangeStamp(); 362 363 DriveMetadataStore::URLAndDriveMetadataList to_be_fetched_files; 364 status = metadata_store_->GetToBeFetchedFiles(&to_be_fetched_files); 365 DCHECK_EQ(SYNC_STATUS_OK, status); 366 typedef DriveMetadataStore::URLAndDriveMetadataList::const_iterator iterator; 367 for (iterator itr = to_be_fetched_files.begin(); 368 itr != to_be_fetched_files.end(); ++itr) { 369 const FileSystemURL& url = itr->first; 370 const DriveMetadata& metadata = itr->second; 371 const std::string& resource_id = metadata.resource_id(); 372 373 SyncFileType file_type = SYNC_FILE_TYPE_FILE; 374 if (metadata.type() == DriveMetadata::RESOURCE_TYPE_FOLDER) 375 file_type = SYNC_FILE_TYPE_DIRECTORY; 376 if (!metadata_store_->IsIncrementalSyncOrigin(url.origin())) { 377 metadata_store_->DeleteEntry(url, base::Bind(&EmptyStatusCallback)); 378 continue; 379 } 380 AppendFetchChange(url.origin(), url.path(), resource_id, file_type); 381 } 382 383 if (!sync_root_resource_id().empty()) 384 api_util_->EnsureSyncRootIsNotInMyDrive(sync_root_resource_id()); 385 386 callback.Run(status); 387 may_have_unfetched_changes_ = true; 388 389 drive::DriveNotificationManager* drive_notification_manager = 390 drive::DriveNotificationManagerFactory::GetForProfile(profile_); 391 if (drive_notification_manager) 392 drive_notification_manager->AddObserver(this); 393 } 394 395 void DriveFileSyncService::UpdateServiceStateFromLastOperationStatus( 396 SyncStatusCode sync_status, 397 google_apis::GDataErrorCode gdata_error) { 398 switch (sync_status) { 399 case SYNC_STATUS_OK: 400 // If the last Drive-related operation was successful we can 401 // change the service state to OK. 402 if (GDataErrorCodeToSyncStatusCode(gdata_error) == SYNC_STATUS_OK) 403 UpdateServiceState(REMOTE_SERVICE_OK, std::string()); 404 break; 405 406 // Authentication error. 407 case SYNC_STATUS_AUTHENTICATION_FAILED: 408 UpdateServiceState(REMOTE_SERVICE_AUTHENTICATION_REQUIRED, 409 "Authentication required"); 410 break; 411 412 // OAuth token error. 413 case SYNC_STATUS_ACCESS_FORBIDDEN: 414 UpdateServiceState(REMOTE_SERVICE_AUTHENTICATION_REQUIRED, 415 "Access forbidden"); 416 break; 417 418 // Errors which could make the service temporarily unavailable. 419 case SYNC_STATUS_RETRY: 420 case SYNC_STATUS_NETWORK_ERROR: 421 case SYNC_STATUS_ABORT: 422 case SYNC_STATUS_FAILED: 423 UpdateServiceState(REMOTE_SERVICE_TEMPORARY_UNAVAILABLE, 424 "Network or temporary service error."); 425 break; 426 427 // Errors which would require manual user intervention to resolve. 428 case SYNC_DATABASE_ERROR_CORRUPTION: 429 case SYNC_DATABASE_ERROR_IO_ERROR: 430 case SYNC_DATABASE_ERROR_FAILED: 431 UpdateServiceState(REMOTE_SERVICE_DISABLED, 432 "Unrecoverable database error"); 433 break; 434 435 default: 436 // Other errors don't affect service state 437 break; 438 } 439 } 440 441 void DriveFileSyncService::UpdateServiceState(RemoteServiceState state, 442 const std::string& description) { 443 RemoteServiceState old_state = GetCurrentState(); 444 state_ = state; 445 446 // Notify remote sync service state if the state has been changed. 447 if (old_state != GetCurrentState()) { 448 util::Log(logging::LOG_INFO, FROM_HERE, 449 "Service state changed: %d->%d: %s", 450 old_state, GetCurrentState(), description.c_str()); 451 FOR_EACH_OBSERVER( 452 Observer, service_observers_, 453 OnRemoteServiceStateUpdated(GetCurrentState(), description)); 454 } 455 } 456 457 void DriveFileSyncService::DoRegisterOriginForTrackingChanges( 458 const GURL& origin, 459 const SyncStatusCallback& callback) { 460 DCHECK(origin.SchemeIs(extensions::kExtensionScheme)); 461 462 DCHECK(!metadata_store_->IsOriginDisabled(origin)); 463 if (!metadata_store_->GetResourceIdForOrigin(origin).empty()) { 464 callback.Run(SYNC_STATUS_OK); 465 return; 466 } 467 468 EnsureOriginRootDirectory( 469 origin, base::Bind(&DriveFileSyncService::DidGetDriveDirectoryForOrigin, 470 AsWeakPtr(), origin, callback)); 471 } 472 473 void DriveFileSyncService::DoUnregisterOriginForTrackingChanges( 474 const GURL& origin, 475 const SyncStatusCallback& callback) { 476 remote_change_handler_.RemoveChangesForOrigin(origin); 477 pending_batch_sync_origins_.erase(origin); 478 metadata_store_->RemoveOrigin(origin, callback); 479 } 480 481 void DriveFileSyncService::DoEnableOriginForTrackingChanges( 482 const GURL& origin, 483 const SyncStatusCallback& callback) { 484 // If origin cannot be found in disabled list, then it's not a SyncFS app 485 // and should be ignored. 486 if (!metadata_store_->IsOriginDisabled(origin)) { 487 callback.Run(SYNC_STATUS_OK); 488 return; 489 } 490 491 pending_batch_sync_origins_.insert( 492 *metadata_store_->disabled_origins().find(origin)); 493 metadata_store_->EnableOrigin(origin, callback); 494 } 495 496 void DriveFileSyncService::DoDisableOriginForTrackingChanges( 497 const GURL& origin, 498 const SyncStatusCallback& callback) { 499 pending_batch_sync_origins_.erase(origin); 500 if (!metadata_store_->IsIncrementalSyncOrigin(origin)) { 501 callback.Run(SYNC_STATUS_OK); 502 return; 503 } 504 505 remote_change_handler_.RemoveChangesForOrigin(origin); 506 metadata_store_->DisableOrigin(origin, callback); 507 } 508 509 void DriveFileSyncService::DoUninstallOrigin( 510 const GURL& origin, 511 const SyncStatusCallback& callback) { 512 // Because origin management is now split between DriveFileSyncService and 513 // DriveMetadataStore, resource_id must be checked for in two places. 514 std::string resource_id = metadata_store_->GetResourceIdForOrigin(origin); 515 if (resource_id.empty()) { 516 std::map<GURL, std::string>::const_iterator iterator = 517 pending_batch_sync_origins_.find(origin); 518 if (iterator != pending_batch_sync_origins_.end()) 519 resource_id = iterator->second; 520 } 521 522 // An empty resource_id indicates either one of following two cases: 523 // 1) origin is not in metadata_store_ because the extension was never 524 // run or it's not managed by this service, and thus no 525 // origin directory on the remote drive was created. 526 // 2) origin or sync root folder is deleted on Drive. 527 if (resource_id.empty()) { 528 callback.Run(SYNC_STATUS_UNKNOWN_ORIGIN); 529 return; 530 } 531 532 // Convert origin's directory GURL to ResourceID and delete it. Expected MD5 533 // is empty to force delete (i.e. skip conflict resolution). 534 api_util_->DeleteFile(resource_id, 535 std::string(), 536 base::Bind(&DriveFileSyncService::DidUninstallOrigin, 537 AsWeakPtr(), 538 origin, 539 callback)); 540 } 541 542 void DriveFileSyncService::DoProcessRemoteChange( 543 const SyncFileCallback& sync_callback, 544 const SyncStatusCallback& completion_callback) { 545 DCHECK(remote_change_processor_); 546 547 SyncStatusCallback callback = base::Bind( 548 &DriveFileSyncService::DidProcessRemoteChange, AsWeakPtr(), 549 sync_callback, completion_callback); 550 551 if (GetCurrentState() == REMOTE_SERVICE_DISABLED) { 552 callback.Run(SYNC_STATUS_SYNC_DISABLED); 553 return; 554 } 555 556 if (!remote_change_handler_.HasChanges()) { 557 callback.Run(SYNC_STATUS_NO_CHANGE_TO_SYNC); 558 return; 559 } 560 561 RemoteChangeHandler::RemoteChange remote_change; 562 bool has_remote_change = 563 remote_change_handler_.GetChange(&remote_change); 564 DCHECK(has_remote_change); 565 566 DCHECK(!running_remote_sync_task_); 567 running_remote_sync_task_.reset(new drive_backend::RemoteSyncDelegate( 568 this, remote_change)); 569 running_remote_sync_task_->Run(callback); 570 } 571 572 void DriveFileSyncService::DoApplyLocalChange( 573 const FileChange& local_file_change, 574 const base::FilePath& local_file_path, 575 const SyncFileMetadata& local_file_metadata, 576 const FileSystemURL& url, 577 const SyncStatusCallback& callback) { 578 if (GetCurrentState() == REMOTE_SERVICE_DISABLED) { 579 callback.Run(SYNC_STATUS_SYNC_DISABLED); 580 return; 581 } 582 583 if (!metadata_store_->IsIncrementalSyncOrigin(url.origin())) { 584 // We may get called by LocalFileSyncService to sync local changes 585 // for the origins that are disabled. 586 DVLOG(1) << "Got request for stray origin: " << url.origin().spec(); 587 callback.Run(SYNC_STATUS_UNKNOWN_ORIGIN); 588 return; 589 } 590 591 DCHECK(!running_local_sync_task_); 592 running_local_sync_task_.reset(new drive_backend::LocalSyncDelegate( 593 this, local_file_change, local_file_path, local_file_metadata, url)); 594 running_local_sync_task_->Run(base::Bind( 595 &DriveFileSyncService::DidApplyLocalChange, AsWeakPtr(), callback)); 596 } 597 598 void DriveFileSyncService::UpdateRegisteredOrigins() { 599 ExtensionService* extension_service = 600 extensions::ExtensionSystem::Get(profile_)->extension_service(); 601 DCHECK(pending_batch_sync_origins_.empty()); 602 if (!extension_service) 603 return; 604 605 std::vector<GURL> origins; 606 metadata_store_->GetAllOrigins(&origins); 607 608 // Update the status of every origin using status from ExtensionService. 609 for (std::vector<GURL>::const_iterator itr = origins.begin(); 610 itr != origins.end(); ++itr) { 611 std::string extension_id = itr->host(); 612 GURL origin = 613 extensions::Extension::GetBaseURLFromExtensionId(extension_id); 614 615 if (!extension_service->GetInstalledExtension(extension_id)) { 616 // Extension has been uninstalled. 617 UninstallOrigin(origin, base::Bind(&EmptyStatusCallback)); 618 } else if (metadata_store_->IsIncrementalSyncOrigin(origin) && 619 !extension_service->IsExtensionEnabled(extension_id)) { 620 // Incremental Extension has been disabled. 621 metadata_store_->DisableOrigin(origin, base::Bind(&EmptyStatusCallback)); 622 } else if (metadata_store_->IsOriginDisabled(origin) && 623 extension_service->IsExtensionEnabled(extension_id)) { 624 // Extension has been re-enabled. 625 pending_batch_sync_origins_.insert( 626 *metadata_store_->disabled_origins().find(origin)); 627 metadata_store_->EnableOrigin(origin, base::Bind(&EmptyStatusCallback)); 628 } 629 } 630 } 631 632 void DriveFileSyncService::StartBatchSync( 633 const SyncStatusCallback& callback) { 634 DCHECK(GetCurrentState() == REMOTE_SERVICE_OK || may_have_unfetched_changes_); 635 DCHECK(!pending_batch_sync_origins_.empty()); 636 637 GURL origin = pending_batch_sync_origins_.begin()->first; 638 std::string resource_id = pending_batch_sync_origins_.begin()->second; 639 DCHECK(!resource_id.empty()); 640 pending_batch_sync_origins_.erase(pending_batch_sync_origins_.begin()); 641 642 DCHECK(!metadata_store_->IsOriginDisabled(origin)); 643 644 util::Log(logging::LOG_VERBOSE, FROM_HERE, 645 "Start batch sync for: %s", origin.spec().c_str()); 646 647 api_util_->GetLargestChangeStamp( 648 base::Bind(&DriveFileSyncService::DidGetLargestChangeStampForBatchSync, 649 AsWeakPtr(), 650 callback, 651 origin, 652 resource_id)); 653 654 may_have_unfetched_changes_ = false; 655 } 656 657 void DriveFileSyncService::DidGetDriveDirectoryForOrigin( 658 const GURL& origin, 659 const SyncStatusCallback& callback, 660 SyncStatusCode status, 661 const std::string& resource_id) { 662 if (status == SYNC_FILE_ERROR_NOT_FOUND && 663 !sync_root_resource_id().empty()) { 664 // Retry after (re-)creating the sync root directory. 665 metadata_store_->SetSyncRootDirectory(std::string()); 666 EnsureOriginRootDirectory( 667 origin, base::Bind( 668 &DriveFileSyncService::DidGetDriveDirectoryForOrigin, 669 AsWeakPtr(), origin, callback)); 670 return; 671 } 672 673 if (status != SYNC_STATUS_OK) { 674 callback.Run(status); 675 return; 676 } 677 678 if (!metadata_store_->IsKnownOrigin(origin)) 679 pending_batch_sync_origins_.insert(std::make_pair(origin, resource_id)); 680 681 callback.Run(SYNC_STATUS_OK); 682 } 683 684 void DriveFileSyncService::DidUninstallOrigin( 685 const GURL& origin, 686 const SyncStatusCallback& callback, 687 google_apis::GDataErrorCode error) { 688 SyncStatusCode status = GDataErrorCodeToSyncStatusCodeWrapper(error); 689 if (status != SYNC_STATUS_OK && status != SYNC_FILE_ERROR_NOT_FOUND) { 690 callback.Run(status); 691 return; 692 } 693 694 // Origin directory has been removed so it's now safe to remove the origin 695 // from the metadata store. 696 DoUnregisterOriginForTrackingChanges(origin, callback); 697 } 698 699 void DriveFileSyncService::DidGetLargestChangeStampForBatchSync( 700 const SyncStatusCallback& callback, 701 const GURL& origin, 702 const std::string& resource_id, 703 google_apis::GDataErrorCode error, 704 int64 largest_changestamp) { 705 if (error != google_apis::HTTP_SUCCESS) { 706 pending_batch_sync_origins_.insert(std::make_pair(origin, resource_id)); 707 callback.Run(GDataErrorCodeToSyncStatusCodeWrapper(error)); 708 return; 709 } 710 711 if (metadata_store_->incremental_sync_origins().empty()) { 712 largest_fetched_changestamp_ = largest_changestamp; 713 metadata_store_->SetLargestChangeStamp( 714 largest_changestamp, 715 base::Bind(&EmptyStatusCallback)); 716 } 717 718 api_util_->ListFiles( 719 resource_id, 720 base::Bind(&DriveFileSyncService::DidGetDirectoryContentForBatchSync, 721 AsWeakPtr(), 722 callback, 723 origin, 724 resource_id, 725 largest_changestamp)); 726 } 727 728 void DriveFileSyncService::DidGetDirectoryContentForBatchSync( 729 const SyncStatusCallback& callback, 730 const GURL& origin, 731 const std::string& resource_id, 732 int64 largest_changestamp, 733 google_apis::GDataErrorCode error, 734 scoped_ptr<google_apis::ResourceList> feed) { 735 if (error != google_apis::HTTP_SUCCESS) { 736 pending_batch_sync_origins_.insert(std::make_pair(origin, resource_id)); 737 callback.Run(GDataErrorCodeToSyncStatusCodeWrapper(error)); 738 return; 739 } 740 741 typedef ScopedVector<google_apis::ResourceEntry>::const_iterator iterator; 742 for (iterator itr = feed->entries().begin(); 743 itr != feed->entries().end(); ++itr) { 744 const google_apis::ResourceEntry& entry = **itr; 745 if (entry.deleted()) 746 continue; 747 748 SyncFileType file_type = SYNC_FILE_TYPE_UNKNOWN; 749 if (entry.is_file()) 750 file_type = SYNC_FILE_TYPE_FILE; 751 else if (entry.is_folder() && IsSyncFSDirectoryOperationEnabled()) 752 file_type = SYNC_FILE_TYPE_DIRECTORY; 753 else 754 continue; 755 756 // Save to be fetched file to DB for restore in case of crash. 757 DriveMetadata metadata; 758 metadata.set_resource_id(entry.resource_id()); 759 metadata.set_md5_checksum(std::string()); 760 metadata.set_conflicted(false); 761 metadata.set_to_be_fetched(true); 762 763 base::FilePath path = TitleToPath(entry.title()); 764 fileapi::FileSystemURL url(CreateSyncableFileSystemURL( 765 origin, path)); 766 // TODO(calvinlo): Write metadata and origin data as single batch command 767 // so it's not possible for the DB to contain a DriveMetadata with an 768 // unknown origin. 769 metadata_store_->UpdateEntry(url, metadata, 770 base::Bind(&EmptyStatusCallback)); 771 772 AppendFetchChange(origin, path, entry.resource_id(), file_type); 773 } 774 775 GURL next_feed_url; 776 if (feed->GetNextFeedURL(&next_feed_url)) { 777 api_util_->ContinueListing( 778 next_feed_url, 779 base::Bind(&DriveFileSyncService::DidGetDirectoryContentForBatchSync, 780 AsWeakPtr(), 781 callback, 782 origin, 783 resource_id, 784 largest_changestamp)); 785 return; 786 } 787 788 metadata_store_->AddIncrementalSyncOrigin(origin, resource_id); 789 may_have_unfetched_changes_ = true; 790 callback.Run(SYNC_STATUS_OK); 791 } 792 793 void DriveFileSyncService::DidProcessRemoteChange( 794 const SyncFileCallback& sync_callback, 795 const SyncStatusCallback& completion_callback, 796 SyncStatusCode status) { 797 fileapi::FileSystemURL url; 798 if (running_remote_sync_task_) 799 url = running_remote_sync_task_->url(); 800 running_remote_sync_task_.reset(); 801 802 completion_callback.Run(status); 803 sync_callback.Run(status, url); 804 } 805 806 void DriveFileSyncService::DidApplyLocalChange( 807 const SyncStatusCallback& callback, 808 SyncStatusCode status) { 809 running_local_sync_task_.reset(); 810 callback.Run(status); 811 } 812 813 bool DriveFileSyncService::AppendRemoteChange( 814 const GURL& origin, 815 const google_apis::ResourceEntry& entry, 816 int64 changestamp) { 817 base::FilePath path = TitleToPath(entry.title()); 818 819 if (!entry.is_folder() && !entry.is_file() && !entry.deleted()) 820 return false; 821 822 if (entry.is_folder() && !IsSyncFSDirectoryOperationEnabled()) 823 return false; 824 825 SyncFileType file_type = entry.is_file() ? 826 SYNC_FILE_TYPE_FILE : SYNC_FILE_TYPE_DIRECTORY; 827 828 return AppendRemoteChangeInternal( 829 origin, path, entry.deleted(), 830 entry.resource_id(), changestamp, 831 entry.deleted() ? std::string() : entry.file_md5(), 832 entry.updated_time(), file_type); 833 } 834 835 bool DriveFileSyncService::AppendFetchChange( 836 const GURL& origin, 837 const base::FilePath& path, 838 const std::string& resource_id, 839 SyncFileType type) { 840 return AppendRemoteChangeInternal( 841 origin, path, 842 false, // is_deleted 843 resource_id, 844 0, // changestamp 845 std::string(), // remote_file_md5 846 base::Time(), // updated_time 847 type); 848 } 849 850 bool DriveFileSyncService::AppendRemoteChangeInternal( 851 const GURL& origin, 852 const base::FilePath& path, 853 bool is_deleted, 854 const std::string& remote_resource_id, 855 int64 changestamp, 856 const std::string& remote_file_md5, 857 const base::Time& updated_time, 858 SyncFileType file_type) { 859 fileapi::FileSystemURL url(CreateSyncableFileSystemURL(origin, path)); 860 DCHECK(url.is_valid()); 861 862 // Note that we create a normalized path from url.path() rather than 863 // path here (as FileSystemURL does extra normalization). 864 base::FilePath::StringType normalized_path = 865 fileapi::VirtualPath::GetNormalizedFilePath(url.path()); 866 867 std::string local_resource_id; 868 std::string local_file_md5; 869 870 DriveMetadata metadata; 871 bool has_db_entry = 872 (metadata_store_->ReadEntry(url, &metadata) == SYNC_STATUS_OK); 873 if (has_db_entry) { 874 local_resource_id = metadata.resource_id(); 875 if (!metadata.to_be_fetched()) 876 local_file_md5 = metadata.md5_checksum(); 877 } 878 879 RemoteChangeHandler::RemoteChange pending_change; 880 if (remote_change_handler_.GetChangeForURL(url, &pending_change)) { 881 if (pending_change.changestamp >= changestamp) 882 return false; 883 884 if (pending_change.change.IsDelete()) { 885 local_resource_id.clear(); 886 local_file_md5.clear(); 887 } else { 888 local_resource_id = pending_change.resource_id; 889 local_file_md5 = pending_change.md5_checksum; 890 } 891 } 892 893 // Drop the change if remote update change does not change file content. 894 if (!remote_file_md5.empty() && 895 !local_file_md5.empty() && 896 remote_file_md5 == local_file_md5) 897 return false; 898 899 // Drop any change if the change has unknown resource id. 900 if (!remote_resource_id.empty() && 901 !local_resource_id.empty() && 902 remote_resource_id != local_resource_id) 903 return false; 904 905 if (is_deleted) { 906 // Drop any change if the change is for deletion and local resource id is 907 // empty. 908 if (local_resource_id.empty()) 909 return false; 910 911 // Determine a file type of the deleted change by local metadata. 912 if (!remote_resource_id.empty() && 913 !local_resource_id.empty() && 914 remote_resource_id == local_resource_id) { 915 DCHECK(IsSyncFSDirectoryOperationEnabled() || 916 DriveMetadata::RESOURCE_TYPE_FILE == metadata.type()); 917 file_type = metadata.type() == DriveMetadata::RESOURCE_TYPE_FILE ? 918 SYNC_FILE_TYPE_FILE : SYNC_FILE_TYPE_DIRECTORY; 919 } 920 921 if (has_db_entry) { 922 metadata.set_resource_id(std::string()); 923 metadata_store_->UpdateEntry(url, metadata, 924 base::Bind(&EmptyStatusCallback)); 925 } 926 } 927 928 FileChange file_change(is_deleted ? FileChange::FILE_CHANGE_DELETE 929 : FileChange::FILE_CHANGE_ADD_OR_UPDATE, 930 file_type); 931 932 RemoteChangeHandler::RemoteChange remote_change( 933 changestamp, remote_resource_id, remote_file_md5, 934 updated_time, url, file_change); 935 remote_change_handler_.AppendChange(remote_change); 936 937 DVLOG(3) << "Append remote change: " << path.value() 938 << " (" << normalized_path << ")" 939 << "@" << changestamp << " " 940 << file_change.DebugString(); 941 942 return true; 943 } 944 945 void DriveFileSyncService::RemoveRemoteChange( 946 const FileSystemURL& url) { 947 remote_change_handler_.RemoveChangeForURL(url); 948 } 949 950 void DriveFileSyncService::MarkConflict( 951 const fileapi::FileSystemURL& url, 952 DriveMetadata* drive_metadata, 953 const SyncStatusCallback& callback) { 954 DCHECK(drive_metadata); 955 DCHECK(!drive_metadata->resource_id().empty()); 956 drive_metadata->set_conflicted(true); 957 drive_metadata->set_to_be_fetched(false); 958 metadata_store_->UpdateEntry( 959 url, *drive_metadata, base::Bind( 960 &DriveFileSyncService::NotifyConflict, 961 AsWeakPtr(), url, callback)); 962 } 963 964 void DriveFileSyncService::NotifyConflict( 965 const fileapi::FileSystemURL& url, 966 const SyncStatusCallback& callback, 967 SyncStatusCode status) { 968 if (status != SYNC_STATUS_OK) { 969 callback.Run(status); 970 return; 971 } 972 NotifyObserversFileStatusChanged(url, 973 SYNC_FILE_STATUS_CONFLICTING, 974 SYNC_ACTION_NONE, 975 SYNC_DIRECTION_NONE); 976 callback.Run(status); 977 } 978 979 SyncStatusCode DriveFileSyncService::GDataErrorCodeToSyncStatusCodeWrapper( 980 google_apis::GDataErrorCode error) { 981 last_gdata_error_ = error; 982 SyncStatusCode status = GDataErrorCodeToSyncStatusCode(error); 983 if (status != SYNC_STATUS_OK && !api_util_->IsAuthenticated()) 984 return SYNC_STATUS_AUTHENTICATION_FAILED; 985 return status; 986 } 987 988 void DriveFileSyncService::MaybeStartFetchChanges() { 989 if (GetCurrentState() == REMOTE_SERVICE_DISABLED) 990 return; 991 992 // If we have pending_batch_sync_origins, try starting the batch sync. 993 if (!pending_batch_sync_origins_.empty()) { 994 if (GetCurrentState() == REMOTE_SERVICE_OK || may_have_unfetched_changes_) { 995 task_manager_->ScheduleTaskIfIdle( 996 base::Bind(&DriveFileSyncService::StartBatchSync, AsWeakPtr())); 997 } 998 return; 999 } 1000 1001 if (may_have_unfetched_changes_ && 1002 !metadata_store_->incremental_sync_origins().empty()) { 1003 task_manager_->ScheduleTaskIfIdle( 1004 base::Bind(&DriveFileSyncService::FetchChangesForIncrementalSync, 1005 AsWeakPtr())); 1006 } 1007 } 1008 1009 void DriveFileSyncService::OnNotificationReceived() { 1010 VLOG(2) << "Notification received to check for Google Drive updates"; 1011 1012 // Likely indicating the network is enabled again. 1013 UpdateServiceState(REMOTE_SERVICE_OK, "Got push notification for Drive."); 1014 1015 // TODO(calvinlo): Try to eliminate may_have_unfetched_changes_ variable. 1016 may_have_unfetched_changes_ = true; 1017 MaybeStartFetchChanges(); 1018 } 1019 1020 void DriveFileSyncService::OnPushNotificationEnabled(bool enabled) { 1021 VLOG(2) << "XMPP Push notification is " << (enabled ? "enabled" : "disabled"); 1022 } 1023 1024 void DriveFileSyncService::MaybeScheduleNextTask() { 1025 if (GetCurrentState() == REMOTE_SERVICE_DISABLED) 1026 return; 1027 1028 // Notify observer of the update of |pending_changes_|. 1029 FOR_EACH_OBSERVER(Observer, service_observers_, 1030 OnRemoteChangeQueueUpdated( 1031 remote_change_handler_.ChangesSize())); 1032 1033 MaybeStartFetchChanges(); 1034 } 1035 1036 void DriveFileSyncService::NotifyLastOperationStatus( 1037 SyncStatusCode sync_status) { 1038 UpdateServiceStateFromLastOperationStatus(sync_status, last_gdata_error_); 1039 } 1040 1041 // static 1042 std::string DriveFileSyncService::PathToTitle(const base::FilePath& path) { 1043 if (!IsSyncFSDirectoryOperationEnabled()) 1044 return path.AsUTF8Unsafe(); 1045 1046 return fileapi::FilePathToString( 1047 base::FilePath(fileapi::VirtualPath::GetNormalizedFilePath(path))); 1048 } 1049 1050 // static 1051 base::FilePath DriveFileSyncService::TitleToPath(const std::string& title) { 1052 if (!IsSyncFSDirectoryOperationEnabled()) 1053 return base::FilePath::FromUTF8Unsafe(title); 1054 1055 return fileapi::StringToFilePath(title).NormalizePathSeparators(); 1056 } 1057 1058 // static 1059 DriveMetadata::ResourceType 1060 DriveFileSyncService::SyncFileTypeToDriveMetadataResourceType( 1061 SyncFileType file_type) { 1062 DCHECK_NE(SYNC_FILE_TYPE_UNKNOWN, file_type); 1063 switch (file_type) { 1064 case SYNC_FILE_TYPE_UNKNOWN: 1065 return DriveMetadata_ResourceType_RESOURCE_TYPE_FILE; 1066 case SYNC_FILE_TYPE_FILE: 1067 return DriveMetadata_ResourceType_RESOURCE_TYPE_FILE; 1068 case SYNC_FILE_TYPE_DIRECTORY: 1069 return DriveMetadata_ResourceType_RESOURCE_TYPE_FOLDER; 1070 } 1071 NOTREACHED(); 1072 return DriveMetadata_ResourceType_RESOURCE_TYPE_FILE; 1073 } 1074 1075 // static 1076 SyncFileType DriveFileSyncService::DriveMetadataResourceTypeToSyncFileType( 1077 DriveMetadata::ResourceType resource_type) { 1078 switch (resource_type) { 1079 case DriveMetadata_ResourceType_RESOURCE_TYPE_FILE: 1080 return SYNC_FILE_TYPE_FILE; 1081 case DriveMetadata_ResourceType_RESOURCE_TYPE_FOLDER: 1082 return SYNC_FILE_TYPE_DIRECTORY; 1083 } 1084 NOTREACHED(); 1085 return SYNC_FILE_TYPE_UNKNOWN; 1086 } 1087 1088 void DriveFileSyncService::FetchChangesForIncrementalSync( 1089 const SyncStatusCallback& callback) { 1090 DCHECK(may_have_unfetched_changes_); 1091 DCHECK(pending_batch_sync_origins_.empty()); 1092 DCHECK(!metadata_store_->incremental_sync_origins().empty()); 1093 1094 DVLOG(1) << "FetchChangesForIncrementalSync (start_changestamp:" 1095 << (largest_fetched_changestamp_ + 1) << ")"; 1096 1097 api_util_->ListChanges( 1098 largest_fetched_changestamp_ + 1, 1099 base::Bind(&DriveFileSyncService::DidFetchChangesForIncrementalSync, 1100 AsWeakPtr(), 1101 callback, 1102 false)); 1103 1104 may_have_unfetched_changes_ = false; 1105 } 1106 1107 void DriveFileSyncService::DidFetchChangesForIncrementalSync( 1108 const SyncStatusCallback& callback, 1109 bool has_new_changes, 1110 google_apis::GDataErrorCode error, 1111 scoped_ptr<google_apis::ResourceList> changes) { 1112 if (error != google_apis::HTTP_SUCCESS) { 1113 callback.Run(GDataErrorCodeToSyncStatusCodeWrapper(error)); 1114 return; 1115 } 1116 1117 bool reset_sync_root = false; 1118 std::set<GURL> reset_origins; 1119 1120 typedef ScopedVector<google_apis::ResourceEntry>::const_iterator iterator; 1121 for (iterator itr = changes->entries().begin(); 1122 itr != changes->entries().end(); ++itr) { 1123 const google_apis::ResourceEntry& entry = **itr; 1124 1125 if (entry.deleted()) { 1126 // Check if the sync root or origin root folder is deleted. 1127 // (We reset resource_id after the for loop so that we can handle 1128 // recursive delete for the origin (at least in this feed) 1129 // while GetOriginForEntry for the origin still works.) 1130 if (entry.resource_id() == sync_root_resource_id()) { 1131 reset_sync_root = true; 1132 continue; 1133 } 1134 GURL origin; 1135 if (metadata_store_->GetOriginByOriginRootDirectoryId( 1136 entry.resource_id(), &origin)) { 1137 reset_origins.insert(origin); 1138 continue; 1139 } 1140 } 1141 1142 GURL origin; 1143 if (!GetOriginForEntry(entry, &origin)) 1144 continue; 1145 1146 DVLOG(3) << " * change:" << entry.title() 1147 << (entry.deleted() ? " (deleted)" : " ") 1148 << "[" << origin.spec() << "]"; 1149 has_new_changes = AppendRemoteChange( 1150 origin, entry, entry.changestamp()) || has_new_changes; 1151 } 1152 1153 if (reset_sync_root) { 1154 util::Log(logging::LOG_WARNING, 1155 FROM_HERE, 1156 "Detected unexpected SyncRoot deletion."); 1157 metadata_store_->SetSyncRootDirectory(std::string()); 1158 } 1159 for (std::set<GURL>::iterator itr = reset_origins.begin(); 1160 itr != reset_origins.end(); ++itr) { 1161 util::Log(logging::LOG_WARNING, 1162 FROM_HERE, 1163 "Detected unexpected OriginRoot deletion: %s", 1164 itr->spec().c_str()); 1165 pending_batch_sync_origins_.erase(*itr); 1166 metadata_store_->SetOriginRootDirectory(*itr, std::string()); 1167 } 1168 1169 GURL next_feed; 1170 if (changes->GetNextFeedURL(&next_feed)) 1171 may_have_unfetched_changes_ = true; 1172 1173 if (!changes->entries().empty()) 1174 largest_fetched_changestamp_ = changes->entries().back()->changestamp(); 1175 1176 callback.Run(SYNC_STATUS_OK); 1177 } 1178 1179 bool DriveFileSyncService::GetOriginForEntry( 1180 const google_apis::ResourceEntry& entry, 1181 GURL* origin_out) { 1182 typedef ScopedVector<google_apis::Link>::const_iterator iterator; 1183 for (iterator itr = entry.links().begin(); 1184 itr != entry.links().end(); ++itr) { 1185 if ((*itr)->type() != google_apis::Link::LINK_PARENT) 1186 continue; 1187 1188 std::string resource_id( 1189 drive::util::ExtractResourceIdFromUrl((*itr)->href())); 1190 if (resource_id.empty()) 1191 continue; 1192 1193 GURL origin; 1194 metadata_store_->GetOriginByOriginRootDirectoryId(resource_id, &origin); 1195 if (!origin.is_valid() || !metadata_store_->IsIncrementalSyncOrigin(origin)) 1196 continue; 1197 1198 *origin_out = origin; 1199 return true; 1200 } 1201 return false; 1202 } 1203 1204 void DriveFileSyncService::NotifyObserversFileStatusChanged( 1205 const FileSystemURL& url, 1206 SyncFileStatus sync_status, 1207 SyncAction action_taken, 1208 SyncDirection direction) { 1209 if (sync_status != SYNC_FILE_STATUS_SYNCED) { 1210 DCHECK_EQ(SYNC_ACTION_NONE, action_taken); 1211 DCHECK_EQ(SYNC_DIRECTION_NONE, direction); 1212 } 1213 1214 FOR_EACH_OBSERVER( 1215 FileStatusObserver, file_status_observers_, 1216 OnFileStatusChanged(url, sync_status, action_taken, direction)); 1217 } 1218 1219 void DriveFileSyncService::EnsureSyncRootDirectory( 1220 const ResourceIdCallback& callback) { 1221 if (!sync_root_resource_id().empty()) { 1222 callback.Run(SYNC_STATUS_OK, sync_root_resource_id()); 1223 return; 1224 } 1225 1226 api_util_->GetDriveDirectoryForSyncRoot(base::Bind( 1227 &DriveFileSyncService::DidEnsureSyncRoot, AsWeakPtr(), callback)); 1228 } 1229 1230 void DriveFileSyncService::DidEnsureSyncRoot( 1231 const ResourceIdCallback& callback, 1232 google_apis::GDataErrorCode error, 1233 const std::string& sync_root_resource_id) { 1234 SyncStatusCode status = GDataErrorCodeToSyncStatusCodeWrapper(error); 1235 if (status == SYNC_STATUS_OK) 1236 metadata_store_->SetSyncRootDirectory(sync_root_resource_id); 1237 callback.Run(status, sync_root_resource_id); 1238 } 1239 1240 void DriveFileSyncService::EnsureOriginRootDirectory( 1241 const GURL& origin, 1242 const ResourceIdCallback& callback) { 1243 std::string resource_id = metadata_store_->GetResourceIdForOrigin(origin); 1244 if (!resource_id.empty()) { 1245 callback.Run(SYNC_STATUS_OK, resource_id); 1246 return; 1247 } 1248 1249 EnsureSyncRootDirectory(base::Bind( 1250 &DriveFileSyncService::DidEnsureSyncRootForOriginRoot, 1251 AsWeakPtr(), origin, callback)); 1252 } 1253 1254 void DriveFileSyncService::DidEnsureSyncRootForOriginRoot( 1255 const GURL& origin, 1256 const ResourceIdCallback& callback, 1257 SyncStatusCode status, 1258 const std::string& sync_root_resource_id) { 1259 if (status != SYNC_STATUS_OK) { 1260 callback.Run(status, std::string()); 1261 return; 1262 } 1263 1264 api_util_->GetDriveDirectoryForOrigin( 1265 sync_root_resource_id, 1266 origin, 1267 base::Bind(&DriveFileSyncService::DidEnsureOriginRoot, 1268 AsWeakPtr(), 1269 origin, 1270 callback)); 1271 } 1272 1273 void DriveFileSyncService::DidEnsureOriginRoot( 1274 const GURL& origin, 1275 const ResourceIdCallback& callback, 1276 google_apis::GDataErrorCode error, 1277 const std::string& resource_id) { 1278 SyncStatusCode status = GDataErrorCodeToSyncStatusCodeWrapper(error); 1279 if (status == SYNC_STATUS_OK && 1280 metadata_store_->IsKnownOrigin(origin)) { 1281 metadata_store_->SetOriginRootDirectory(origin, resource_id); 1282 } 1283 callback.Run(status, resource_id); 1284 } 1285 1286 std::string DriveFileSyncService::sync_root_resource_id() { 1287 return metadata_store_->sync_root_directory(); 1288 } 1289 1290 } // namespace sync_file_system 1291