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