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