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.
5 #include "chrome/browser/sync_file_system/drive_backend_v1/drive_file_sync_service.h"
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"
45 using fileapi::FileSystemURL;
47 namespace sync_file_system {
49 typedef RemoteFileSyncService::OriginStatusMap OriginStatusMap;
53 const base::FilePath::CharType kTempDirName[] = FILE_PATH_LITERAL("tmp");
55 void EmptyStatusCallback(SyncStatusCode status) {}
57 void RemoteVersionsCallbackAdapter(
58 const DriveFileSyncService::RemoteVersionsCallback& versions_callback,
59 const SyncStatusCallback& completion_callback,
60 SyncStatusCode status,
61 const std::vector<DriveFileSyncService::Version>& versions) {
62 completion_callback.Run(status);
63 versions_callback.Run(status, versions);
66 void DownloadVersionCallbackAdapter(
67 const DriveFileSyncService::DownloadVersionCallback& download_callback,
68 const SyncStatusCallback& completion_callback,
69 SyncStatusCode status,
70 webkit_blob::ScopedFile downloaded) {
71 completion_callback.Run(status);
72 download_callback.Run(status, downloaded.Pass());
77 ConflictResolutionPolicy DriveFileSyncService::kDefaultPolicy =
78 CONFLICT_RESOLUTION_POLICY_LAST_WRITE_WIN;
80 // DriveFileSyncService ------------------------------------------------------
82 DriveFileSyncService::~DriveFileSyncService() {
84 api_util_->RemoveObserver(this);
86 drive::DriveNotificationManager* drive_notification_manager =
87 drive::DriveNotificationManagerFactory::GetForBrowserContext(profile_);
88 if (drive_notification_manager)
89 drive_notification_manager->RemoveObserver(this);
92 scoped_ptr<DriveFileSyncService> DriveFileSyncService::Create(
94 scoped_ptr<DriveFileSyncService> service(new DriveFileSyncService(profile));
95 scoped_ptr<SyncTaskManager> task_manager(
96 new SyncTaskManager(service->AsWeakPtr()));
97 SyncStatusCallback callback = base::Bind(
98 &SyncTaskManager::Initialize, task_manager->AsWeakPtr());
99 service->Initialize(task_manager.Pass(), callback);
100 return service.Pass();
103 void DriveFileSyncService::AppendDependsOnFactories(
104 std::set<BrowserContextKeyedServiceFactory*>* factories) {
106 factories->insert(drive::DriveNotificationManagerFactory::GetInstance());
107 factories->insert(ProfileOAuth2TokenServiceFactory::GetInstance());
109 extensions::ExtensionsBrowserClient::Get()->GetExtensionSystemFactory());
112 scoped_ptr<DriveFileSyncService> DriveFileSyncService::CreateForTesting(
114 const base::FilePath& base_dir,
115 scoped_ptr<drive_backend::APIUtilInterface> api_util,
116 scoped_ptr<DriveMetadataStore> metadata_store) {
117 scoped_ptr<DriveFileSyncService> service(new DriveFileSyncService(profile));
118 scoped_ptr<SyncTaskManager> task_manager(
119 new SyncTaskManager(service->AsWeakPtr()));
120 SyncStatusCallback callback = base::Bind(
121 &SyncTaskManager::Initialize, task_manager->AsWeakPtr());
122 service->InitializeForTesting(task_manager.Pass(),
125 metadata_store.Pass(),
127 return service.Pass();
130 void DriveFileSyncService::AddServiceObserver(Observer* observer) {
131 service_observers_.AddObserver(observer);
134 void DriveFileSyncService::AddFileStatusObserver(
135 FileStatusObserver* observer) {
136 file_status_observers_.AddObserver(observer);
139 void DriveFileSyncService::RegisterOrigin(
141 const SyncStatusCallback& callback) {
142 if (!pending_origin_operations_.HasPendingOperation(origin) &&
143 metadata_store_->IsIncrementalSyncOrigin(origin) &&
144 !metadata_store_->GetResourceIdForOrigin(origin).empty()) {
145 DCHECK(!metadata_store_->IsOriginDisabled(origin));
146 callback.Run(SYNC_STATUS_OK);
147 MaybeStartFetchChanges();
151 pending_origin_operations_.Push(origin, OriginOperation::REGISTERING);
153 task_manager_->ScheduleTaskAtPriority(
154 base::Bind(&DriveFileSyncService::DoRegisterOrigin, AsWeakPtr(), origin),
155 SyncTaskManager::PRIORITY_HIGH,
159 void DriveFileSyncService::EnableOrigin(
161 const SyncStatusCallback& callback) {
162 pending_origin_operations_.Push(origin, OriginOperation::ENABLING);
163 task_manager_->ScheduleTaskAtPriority(
164 base::Bind(&DriveFileSyncService::DoEnableOrigin, AsWeakPtr(), origin),
165 SyncTaskManager::PRIORITY_HIGH,
169 void DriveFileSyncService::DisableOrigin(
171 const SyncStatusCallback& callback) {
172 pending_origin_operations_.Push(origin, OriginOperation::DISABLING);
173 task_manager_->ScheduleTaskAtPriority(
174 base::Bind(&DriveFileSyncService::DoDisableOrigin, AsWeakPtr(), origin),
175 SyncTaskManager::PRIORITY_HIGH,
179 void DriveFileSyncService::UninstallOrigin(
182 const SyncStatusCallback& callback) {
183 pending_origin_operations_.Push(origin, OriginOperation::UNINSTALLING);
184 task_manager_->ScheduleTaskAtPriority(
185 base::Bind(&DriveFileSyncService::DoUninstallOrigin, AsWeakPtr(),
187 SyncTaskManager::PRIORITY_HIGH,
191 void DriveFileSyncService::ProcessRemoteChange(
192 const SyncFileCallback& callback) {
193 task_manager_->ScheduleTask(
194 base::Bind(&DriveFileSyncService::DoProcessRemoteChange, AsWeakPtr(),
196 base::Bind(&EmptyStatusCallback));
199 void DriveFileSyncService::SetRemoteChangeProcessor(
200 RemoteChangeProcessor* processor) {
201 remote_change_processor_ = processor;
204 LocalChangeProcessor* DriveFileSyncService::GetLocalChangeProcessor() {
208 bool DriveFileSyncService::IsConflicting(const FileSystemURL& url) {
209 DriveMetadata metadata;
210 const SyncStatusCode status = metadata_store_->ReadEntry(url, &metadata);
211 if (status != SYNC_STATUS_OK) {
212 DCHECK_EQ(SYNC_DATABASE_ERROR_NOT_FOUND, status);
215 return metadata.conflicted();
218 RemoteServiceState DriveFileSyncService::GetCurrentState() const {
220 return REMOTE_SERVICE_DISABLED;
224 void DriveFileSyncService::GetOriginStatusMap(OriginStatusMap* status_map) {
227 // Add batch sync origins held by DriveFileSyncService.
228 typedef std::map<GURL, std::string>::const_iterator iterator;
229 for (iterator itr = pending_batch_sync_origins_.begin();
230 itr != pending_batch_sync_origins_.end();
232 (*status_map)[itr->first] = "Pending";
234 // Add incremental and disabled origins held by DriveMetadataStore.
235 for (iterator itr = metadata_store_->incremental_sync_origins().begin();
236 itr != metadata_store_->incremental_sync_origins().end();
238 (*status_map)[itr->first] = "Enabled";
240 for (iterator itr = metadata_store_->disabled_origins().begin();
241 itr != metadata_store_->disabled_origins().end();
243 (*status_map)[itr->first] = "Disabled";
246 scoped_ptr<base::ListValue> DriveFileSyncService::DumpFiles(
247 const GURL& origin) {
248 return metadata_store_->DumpFiles(origin);
251 scoped_ptr<base::ListValue> DriveFileSyncService::DumpDatabase() {
252 // Not implemented (yet).
253 return scoped_ptr<base::ListValue>();
256 void DriveFileSyncService::SetSyncEnabled(bool enabled) {
257 if (sync_enabled_ == enabled)
260 RemoteServiceState old_state = GetCurrentState();
261 sync_enabled_ = enabled;
262 if (old_state == GetCurrentState())
265 const char* status_message = enabled ? "Sync is enabled" : "Sync is disabled";
267 Observer, service_observers_,
268 OnRemoteServiceStateUpdated(GetCurrentState(), status_message));
271 SyncStatusCode DriveFileSyncService::SetConflictResolutionPolicy(
272 ConflictResolutionPolicy policy) {
273 conflict_resolution_resolver_.set_policy(policy);
274 return SYNC_STATUS_OK;
277 ConflictResolutionPolicy
278 DriveFileSyncService::GetConflictResolutionPolicy() const {
279 return conflict_resolution_resolver_.policy();
282 void DriveFileSyncService::GetRemoteVersions(
283 const fileapi::FileSystemURL& url,
284 const RemoteVersionsCallback& callback) {
285 task_manager_->ScheduleTask(
286 base::Bind(&DriveFileSyncService::DoGetRemoteVersions, AsWeakPtr(),
288 base::Bind(&EmptyStatusCallback));
291 void DriveFileSyncService::DownloadRemoteVersion(
292 const fileapi::FileSystemURL& url,
293 const std::string& version_id,
294 const DownloadVersionCallback& callback) {
295 task_manager_->ScheduleTask(
296 base::Bind(&DriveFileSyncService::DoDownloadRemoteVersion, AsWeakPtr(),
297 url, version_id, callback),
298 base::Bind(&EmptyStatusCallback));
301 void DriveFileSyncService::PromoteDemotedChanges() {
304 void DriveFileSyncService::ApplyLocalChange(
305 const FileChange& local_file_change,
306 const base::FilePath& local_file_path,
307 const SyncFileMetadata& local_file_metadata,
308 const FileSystemURL& url,
309 const SyncStatusCallback& callback) {
310 task_manager_->ScheduleTask(
311 base::Bind(&DriveFileSyncService::DoApplyLocalChange, AsWeakPtr(),
319 void DriveFileSyncService::OnAuthenticated() {
320 if (state_ == REMOTE_SERVICE_OK)
322 util::Log(logging::LOG_VERBOSE, FROM_HERE, "OnAuthenticated");
324 UpdateServiceState(REMOTE_SERVICE_OK, "Authenticated");
326 may_have_unfetched_changes_ = true;
327 MaybeStartFetchChanges();
330 void DriveFileSyncService::OnNetworkConnected() {
331 if (state_ == REMOTE_SERVICE_OK)
333 util::Log(logging::LOG_VERBOSE, FROM_HERE, "OnNetworkConnected");
335 UpdateServiceState(REMOTE_SERVICE_OK, "Network connected");
337 may_have_unfetched_changes_ = true;
338 MaybeStartFetchChanges();
341 DriveFileSyncService::DriveFileSyncService(Profile* profile)
343 state_(REMOTE_SERVICE_OK),
345 largest_fetched_changestamp_(0),
346 may_have_unfetched_changes_(false),
347 remote_change_processor_(NULL),
348 last_gdata_error_(google_apis::HTTP_SUCCESS),
349 conflict_resolution_resolver_(kDefaultPolicy) {
352 void DriveFileSyncService::Initialize(
353 scoped_ptr<SyncTaskManager> task_manager,
354 const SyncStatusCallback& callback) {
356 DCHECK(!metadata_store_);
357 DCHECK(!task_manager_);
359 task_manager_ = task_manager.Pass();
361 temporary_file_dir_ = sync_file_system::GetSyncFileSystemDir(
362 profile_->GetPath()).Append(kTempDirName);
364 api_util_.reset(new drive_backend::APIUtil(profile_, temporary_file_dir_));
365 api_util_->AddObserver(this);
367 metadata_store_.reset(new DriveMetadataStore(
368 GetSyncFileSystemDir(profile_->GetPath()),
369 content::BrowserThread::GetMessageLoopProxyForThread(
370 content::BrowserThread::FILE).get()));
372 metadata_store_->Initialize(
373 base::Bind(&DriveFileSyncService::DidInitializeMetadataStore,
374 AsWeakPtr(), callback));
377 void DriveFileSyncService::InitializeForTesting(
378 scoped_ptr<SyncTaskManager> task_manager,
379 const base::FilePath& base_dir,
380 scoped_ptr<drive_backend::APIUtilInterface> api_util,
381 scoped_ptr<DriveMetadataStore> metadata_store,
382 const SyncStatusCallback& callback) {
383 DCHECK(!metadata_store_);
384 DCHECK(!task_manager_);
386 task_manager_ = task_manager.Pass();
387 temporary_file_dir_ = base_dir.Append(kTempDirName);
389 api_util_ = api_util.Pass();
390 metadata_store_ = metadata_store.Pass();
392 base::MessageLoopProxy::current()->PostTask(
394 base::Bind(&DriveFileSyncService::DidInitializeMetadataStore,
395 AsWeakPtr(), callback, SYNC_STATUS_OK, false));
398 void DriveFileSyncService::DidInitializeMetadataStore(
399 const SyncStatusCallback& callback,
400 SyncStatusCode status,
402 if (status != SYNC_STATUS_OK) {
403 callback.Run(status);
407 DCHECK(pending_batch_sync_origins_.empty());
409 UpdateRegisteredOrigins();
411 largest_fetched_changestamp_ = metadata_store_->GetLargestChangeStamp();
413 DriveMetadataStore::URLAndDriveMetadataList to_be_fetched_files;
414 status = metadata_store_->GetToBeFetchedFiles(&to_be_fetched_files);
415 DCHECK_EQ(SYNC_STATUS_OK, status);
416 typedef DriveMetadataStore::URLAndDriveMetadataList::const_iterator iterator;
417 for (iterator itr = to_be_fetched_files.begin();
418 itr != to_be_fetched_files.end(); ++itr) {
419 const FileSystemURL& url = itr->first;
420 const DriveMetadata& metadata = itr->second;
421 const std::string& resource_id = metadata.resource_id();
423 SyncFileType file_type = SYNC_FILE_TYPE_FILE;
424 if (metadata.type() == DriveMetadata::RESOURCE_TYPE_FOLDER)
425 file_type = SYNC_FILE_TYPE_DIRECTORY;
426 if (!metadata_store_->IsIncrementalSyncOrigin(url.origin())) {
427 metadata_store_->DeleteEntry(url, base::Bind(&EmptyStatusCallback));
430 AppendFetchChange(url.origin(), url.path(), resource_id, file_type);
433 if (!sync_root_resource_id().empty())
434 api_util_->EnsureSyncRootIsNotInMyDrive(sync_root_resource_id());
436 callback.Run(status);
437 may_have_unfetched_changes_ = true;
439 drive::DriveNotificationManager* drive_notification_manager =
440 drive::DriveNotificationManagerFactory::GetForBrowserContext(profile_);
441 if (drive_notification_manager)
442 drive_notification_manager->AddObserver(this);
445 void DriveFileSyncService::UpdateServiceStateFromLastOperationStatus(
446 SyncStatusCode sync_status,
447 google_apis::GDataErrorCode gdata_error) {
448 switch (sync_status) {
450 // If the last Drive-related operation was successful we can
451 // change the service state to OK.
452 if (drive_backend::GDataErrorCodeToSyncStatusCode(gdata_error) ==
454 UpdateServiceState(REMOTE_SERVICE_OK, std::string());
457 // Authentication error.
458 case SYNC_STATUS_AUTHENTICATION_FAILED:
459 UpdateServiceState(REMOTE_SERVICE_AUTHENTICATION_REQUIRED,
460 "Authentication required");
463 // OAuth token error.
464 case SYNC_STATUS_ACCESS_FORBIDDEN:
465 UpdateServiceState(REMOTE_SERVICE_AUTHENTICATION_REQUIRED,
469 // Errors which could make the service temporarily unavailable.
470 case SYNC_STATUS_SERVICE_TEMPORARILY_UNAVAILABLE:
471 case SYNC_STATUS_NETWORK_ERROR:
472 case SYNC_STATUS_ABORT:
473 case SYNC_STATUS_FAILED:
474 UpdateServiceState(REMOTE_SERVICE_TEMPORARY_UNAVAILABLE,
475 "Network or temporary service error.");
478 // Errors which would require manual user intervention to resolve.
479 case SYNC_DATABASE_ERROR_CORRUPTION:
480 case SYNC_DATABASE_ERROR_IO_ERROR:
481 case SYNC_DATABASE_ERROR_FAILED:
482 UpdateServiceState(REMOTE_SERVICE_DISABLED,
483 "Unrecoverable database error");
487 // Other errors don't affect service state
492 void DriveFileSyncService::UpdateServiceState(RemoteServiceState state,
493 const std::string& description) {
494 RemoteServiceState old_state = GetCurrentState();
497 // Notify remote sync service state if the state has been changed.
498 if (old_state != GetCurrentState()) {
499 util::Log(logging::LOG_VERBOSE, FROM_HERE,
500 "Service state changed: %d->%d: %s",
501 old_state, GetCurrentState(), description.c_str());
503 Observer, service_observers_,
504 OnRemoteServiceStateUpdated(GetCurrentState(), description));
508 void DriveFileSyncService::DoRegisterOrigin(
510 const SyncStatusCallback& callback) {
511 DCHECK(origin.SchemeIs(extensions::kExtensionScheme));
513 OriginOperation op = pending_origin_operations_.Pop();
514 DCHECK_EQ(origin, op.origin);
515 DCHECK_EQ(OriginOperation::REGISTERING, op.type);
517 DCHECK(!metadata_store_->IsOriginDisabled(origin));
518 if (!metadata_store_->GetResourceIdForOrigin(origin).empty()) {
519 callback.Run(SYNC_STATUS_OK);
523 EnsureOriginRootDirectory(
524 origin, base::Bind(&DriveFileSyncService::DidGetDriveDirectoryForOrigin,
525 AsWeakPtr(), origin, callback));
528 void DriveFileSyncService::DoEnableOrigin(
530 const SyncStatusCallback& callback) {
531 OriginOperation op = pending_origin_operations_.Pop();
532 DCHECK_EQ(origin, op.origin);
533 DCHECK_EQ(OriginOperation::ENABLING, op.type);
535 // If origin cannot be found in disabled list, then it's not a SyncFS app
536 // and should be ignored.
537 if (!metadata_store_->IsOriginDisabled(origin)) {
538 callback.Run(SYNC_STATUS_OK);
542 pending_batch_sync_origins_.insert(
543 *metadata_store_->disabled_origins().find(origin));
544 metadata_store_->EnableOrigin(origin, callback);
547 void DriveFileSyncService::DoDisableOrigin(
549 const SyncStatusCallback& callback) {
550 OriginOperation op = pending_origin_operations_.Pop();
551 DCHECK_EQ(origin, op.origin);
552 DCHECK_EQ(OriginOperation::DISABLING, op.type);
554 pending_batch_sync_origins_.erase(origin);
555 if (!metadata_store_->IsIncrementalSyncOrigin(origin)) {
556 callback.Run(SYNC_STATUS_OK);
560 remote_change_handler_.RemoveChangesForOrigin(origin);
561 metadata_store_->DisableOrigin(origin, callback);
564 void DriveFileSyncService::DoUninstallOrigin(
567 const SyncStatusCallback& callback) {
568 OriginOperation op = pending_origin_operations_.Pop();
569 DCHECK_EQ(origin, op.origin);
570 DCHECK_EQ(OriginOperation::UNINSTALLING, op.type);
572 // Because origin management is now split between DriveFileSyncService and
573 // DriveMetadataStore, resource_id must be checked for in two places.
574 std::string resource_id = metadata_store_->GetResourceIdForOrigin(origin);
575 if (resource_id.empty()) {
576 std::map<GURL, std::string>::const_iterator iterator =
577 pending_batch_sync_origins_.find(origin);
578 if (iterator != pending_batch_sync_origins_.end())
579 resource_id = iterator->second;
582 // An empty resource_id indicates either one of following two cases:
583 // 1) origin is not in metadata_store_ because the extension was never
584 // run or it's not managed by this service, and thus no
585 // origin directory on the remote drive was created.
586 // 2) origin or sync root folder is deleted on Drive.
587 if (resource_id.empty()) {
588 if (metadata_store_->IsKnownOrigin(origin))
589 DidUninstallOrigin(origin, callback, google_apis::HTTP_SUCCESS);
591 callback.Run(SYNC_STATUS_UNKNOWN_ORIGIN);
595 if (flag == UNINSTALL_AND_KEEP_REMOTE) {
596 DidUninstallOrigin(origin, callback, google_apis::HTTP_SUCCESS);
600 // Convert origin's directory GURL to ResourceID and delete it. Expected MD5
601 // is empty to force delete (i.e. skip conflict resolution).
602 api_util_->DeleteFile(resource_id,
604 base::Bind(&DriveFileSyncService::DidUninstallOrigin,
610 void DriveFileSyncService::DoProcessRemoteChange(
611 const SyncFileCallback& sync_callback,
612 const SyncStatusCallback& completion_callback) {
613 DCHECK(remote_change_processor_);
615 SyncStatusCallback callback = base::Bind(
616 &DriveFileSyncService::DidProcessRemoteChange, AsWeakPtr(),
617 sync_callback, completion_callback);
619 if (GetCurrentState() == REMOTE_SERVICE_DISABLED) {
620 callback.Run(SYNC_STATUS_SYNC_DISABLED);
624 if (!remote_change_handler_.HasChanges()) {
625 callback.Run(SYNC_STATUS_NO_CHANGE_TO_SYNC);
629 RemoteChangeHandler::RemoteChange remote_change;
630 bool has_remote_change =
631 remote_change_handler_.GetChange(&remote_change);
632 DCHECK(has_remote_change);
634 DCHECK(!running_remote_sync_task_);
635 running_remote_sync_task_.reset(new drive_backend::RemoteSyncDelegate(
636 this, remote_change));
637 running_remote_sync_task_->Run(callback);
640 void DriveFileSyncService::DoApplyLocalChange(
641 const FileChange& local_file_change,
642 const base::FilePath& local_file_path,
643 const SyncFileMetadata& local_file_metadata,
644 const FileSystemURL& url,
645 const SyncStatusCallback& callback) {
646 if (GetCurrentState() == REMOTE_SERVICE_DISABLED) {
647 callback.Run(SYNC_STATUS_SYNC_DISABLED);
651 if (!metadata_store_->IsIncrementalSyncOrigin(url.origin())) {
652 // We may get called by LocalFileSyncService to sync local changes
653 // for the origins that are disabled.
654 DVLOG(1) << "Got request for stray origin: " << url.origin().spec();
655 callback.Run(SYNC_STATUS_UNKNOWN_ORIGIN);
659 DCHECK(!running_local_sync_task_);
660 running_local_sync_task_.reset(new drive_backend::LocalSyncDelegate(
661 this, local_file_change, local_file_path, local_file_metadata, url));
662 running_local_sync_task_->Run(base::Bind(
663 &DriveFileSyncService::DidApplyLocalChange, AsWeakPtr(), callback));
666 void DriveFileSyncService::DoGetRemoteVersions(
667 const fileapi::FileSystemURL& url,
668 const RemoteVersionsCallback& versions_callback,
669 const SyncStatusCallback& completion_callback) {
670 RemoteVersionsCallback callback =
671 base::Bind(&RemoteVersionsCallbackAdapter,
672 versions_callback, completion_callback);
674 DriveMetadata drive_metadata;
675 SyncStatusCode status = metadata_store_->ReadEntry(url, &drive_metadata);
676 if (drive_metadata.resource_id().empty())
677 status = SYNC_DATABASE_ERROR_NOT_FOUND;
678 if (status != SYNC_STATUS_OK) {
679 callback.Run(status, std::vector<Version>());
683 api_util_->GetResourceEntry(
684 drive_metadata.resource_id(),
686 &DriveFileSyncService::DidGetEntryForRemoteVersions,
687 AsWeakPtr(), callback));
690 void DriveFileSyncService::DidGetEntryForRemoteVersions(
691 const RemoteVersionsCallback& callback,
692 google_apis::GDataErrorCode error,
693 scoped_ptr<google_apis::ResourceEntry> entry) {
694 if (error != google_apis::HTTP_SUCCESS) {
695 callback.Run(GDataErrorCodeToSyncStatusCodeWrapper(error),
696 std::vector<Version>());
701 SyncFileType file_type =
702 entry->is_file() ? SYNC_FILE_TYPE_FILE :
703 entry->is_folder() ? SYNC_FILE_TYPE_DIRECTORY :
704 SYNC_FILE_TYPE_UNKNOWN;
707 version.id = "dummy"; // Not used in the current version.
708 version.metadata = SyncFileMetadata(file_type,
710 entry->updated_time());
711 std::vector<Version> versions;
712 versions.push_back(version);
713 callback.Run(SYNC_STATUS_OK, versions);
716 void DriveFileSyncService::DoDownloadRemoteVersion(
717 const fileapi::FileSystemURL& url,
718 const std::string& /* version_id */,
719 const DownloadVersionCallback& download_callback,
720 const SyncStatusCallback& completion_callback) {
721 DownloadVersionCallback callback =
722 base::Bind(&DownloadVersionCallbackAdapter,
723 download_callback, completion_callback);
725 DriveMetadata metadata;
726 if (metadata_store_->ReadEntry(url, &metadata) != SYNC_STATUS_OK) {
727 // The conflict may have been already resolved.
728 callback.Run(SYNC_FILE_ERROR_NOT_FOUND, webkit_blob::ScopedFile());
732 api_util_->DownloadFile(
733 metadata.resource_id(), std::string(),
734 base::Bind(&DriveFileSyncService::DidDownloadVersion, AsWeakPtr(),
738 void DriveFileSyncService::DidDownloadVersion(
739 const DownloadVersionCallback& download_callback,
740 google_apis::GDataErrorCode error,
741 const std::string& file_md5,
743 const base::Time& last_updated,
744 webkit_blob::ScopedFile downloaded) {
745 SyncStatusCode status = GDataErrorCodeToSyncStatusCodeWrapper(error);
746 download_callback.Run(status, downloaded.Pass());
749 void DriveFileSyncService::UpdateRegisteredOrigins() {
750 ExtensionService* extension_service =
751 extensions::ExtensionSystem::Get(profile_)->extension_service();
752 DCHECK(pending_batch_sync_origins_.empty());
753 if (!extension_service)
756 std::vector<GURL> origins;
757 metadata_store_->GetAllOrigins(&origins);
759 // Update the status of every origin using status from ExtensionService.
760 for (std::vector<GURL>::const_iterator itr = origins.begin();
761 itr != origins.end(); ++itr) {
762 std::string extension_id = itr->host();
764 extensions::Extension::GetBaseURLFromExtensionId(extension_id);
766 if (!extension_service->GetInstalledExtension(extension_id)) {
767 // Extension has been uninstalled.
768 // (At this stage we can't know if it was unpacked extension or not,
769 // so just purge the remote folder.)
770 UninstallOrigin(origin,
771 RemoteFileSyncService::UNINSTALL_AND_PURGE_REMOTE,
772 base::Bind(&EmptyStatusCallback));
773 } else if (metadata_store_->IsIncrementalSyncOrigin(origin) &&
774 !extension_service->IsExtensionEnabled(extension_id)) {
775 // Incremental Extension has been disabled.
776 metadata_store_->DisableOrigin(origin, base::Bind(&EmptyStatusCallback));
777 } else if (metadata_store_->IsOriginDisabled(origin) &&
778 extension_service->IsExtensionEnabled(extension_id)) {
779 // Extension has been re-enabled.
780 pending_batch_sync_origins_.insert(
781 *metadata_store_->disabled_origins().find(origin));
782 metadata_store_->EnableOrigin(origin, base::Bind(&EmptyStatusCallback));
787 void DriveFileSyncService::StartBatchSync(
788 const SyncStatusCallback& callback) {
789 DCHECK(GetCurrentState() == REMOTE_SERVICE_OK || may_have_unfetched_changes_);
790 DCHECK(!pending_batch_sync_origins_.empty());
792 GURL origin = pending_batch_sync_origins_.begin()->first;
793 std::string resource_id = pending_batch_sync_origins_.begin()->second;
794 DCHECK(!resource_id.empty());
795 pending_batch_sync_origins_.erase(pending_batch_sync_origins_.begin());
797 DCHECK(!metadata_store_->IsOriginDisabled(origin));
799 util::Log(logging::LOG_VERBOSE, FROM_HERE,
800 "Start batch sync for: %s", origin.spec().c_str());
802 api_util_->GetLargestChangeStamp(
803 base::Bind(&DriveFileSyncService::DidGetLargestChangeStampForBatchSync,
809 may_have_unfetched_changes_ = false;
812 void DriveFileSyncService::DidGetDriveDirectoryForOrigin(
814 const SyncStatusCallback& callback,
815 SyncStatusCode status,
816 const std::string& resource_id) {
817 if (status == SYNC_FILE_ERROR_NOT_FOUND &&
818 !sync_root_resource_id().empty()) {
819 // Retry after (re-)creating the sync root directory.
820 metadata_store_->SetSyncRootDirectory(std::string());
821 EnsureOriginRootDirectory(
823 &DriveFileSyncService::DidGetDriveDirectoryForOrigin,
824 AsWeakPtr(), origin, callback));
828 if (status != SYNC_STATUS_OK) {
829 callback.Run(status);
833 if (!metadata_store_->IsKnownOrigin(origin))
834 pending_batch_sync_origins_.insert(std::make_pair(origin, resource_id));
836 callback.Run(SYNC_STATUS_OK);
839 void DriveFileSyncService::DidUninstallOrigin(
841 const SyncStatusCallback& callback,
842 google_apis::GDataErrorCode error) {
843 SyncStatusCode status = GDataErrorCodeToSyncStatusCodeWrapper(error);
844 if (status != SYNC_STATUS_OK && status != SYNC_FILE_ERROR_NOT_FOUND) {
845 callback.Run(status);
849 // Origin directory has been removed so it's now safe to remove the origin
850 // from the metadata store.
851 remote_change_handler_.RemoveChangesForOrigin(origin);
852 pending_batch_sync_origins_.erase(origin);
853 metadata_store_->RemoveOrigin(origin, callback);
856 void DriveFileSyncService::DidGetLargestChangeStampForBatchSync(
857 const SyncStatusCallback& callback,
859 const std::string& resource_id,
860 google_apis::GDataErrorCode error,
861 int64 largest_changestamp) {
862 if (error != google_apis::HTTP_SUCCESS) {
863 pending_batch_sync_origins_.insert(std::make_pair(origin, resource_id));
864 callback.Run(GDataErrorCodeToSyncStatusCodeWrapper(error));
868 if (metadata_store_->incremental_sync_origins().empty()) {
869 largest_fetched_changestamp_ = largest_changestamp;
870 metadata_store_->SetLargestChangeStamp(
872 base::Bind(&EmptyStatusCallback));
875 api_util_->ListFiles(
877 base::Bind(&DriveFileSyncService::DidGetDirectoryContentForBatchSync,
882 largest_changestamp));
885 void DriveFileSyncService::DidGetDirectoryContentForBatchSync(
886 const SyncStatusCallback& callback,
888 const std::string& resource_id,
889 int64 largest_changestamp,
890 google_apis::GDataErrorCode error,
891 scoped_ptr<google_apis::ResourceList> feed) {
892 if (error != google_apis::HTTP_SUCCESS) {
893 pending_batch_sync_origins_.insert(std::make_pair(origin, resource_id));
894 callback.Run(GDataErrorCodeToSyncStatusCodeWrapper(error));
898 typedef ScopedVector<google_apis::ResourceEntry>::const_iterator iterator;
899 for (iterator itr = feed->entries().begin();
900 itr != feed->entries().end(); ++itr) {
901 const google_apis::ResourceEntry& entry = **itr;
905 SyncFileType file_type = SYNC_FILE_TYPE_UNKNOWN;
907 file_type = SYNC_FILE_TYPE_FILE;
908 else if (entry.is_folder() && IsSyncFSDirectoryOperationEnabled())
909 file_type = SYNC_FILE_TYPE_DIRECTORY;
913 DCHECK(file_type == SYNC_FILE_TYPE_FILE ||
914 file_type == SYNC_FILE_TYPE_DIRECTORY);
916 // Save to be fetched file to DB for restore in case of crash.
917 DriveMetadata metadata;
918 metadata.set_resource_id(entry.resource_id());
919 metadata.set_md5_checksum(std::string());
920 metadata.set_conflicted(false);
921 metadata.set_to_be_fetched(true);
923 if (file_type == SYNC_FILE_TYPE_FILE)
924 metadata.set_type(DriveMetadata::RESOURCE_TYPE_FILE);
926 metadata.set_type(DriveMetadata::RESOURCE_TYPE_FOLDER);
928 base::FilePath path = TitleToPath(entry.title());
929 fileapi::FileSystemURL url(CreateSyncableFileSystemURL(
931 // TODO(calvinlo): Write metadata and origin data as single batch command
932 // so it's not possible for the DB to contain a DriveMetadata with an
934 metadata_store_->UpdateEntry(url, metadata,
935 base::Bind(&EmptyStatusCallback));
937 AppendFetchChange(origin, path, entry.resource_id(), file_type);
941 if (feed->GetNextFeedURL(&next_feed_url)) {
942 api_util_->ContinueListing(
944 base::Bind(&DriveFileSyncService::DidGetDirectoryContentForBatchSync,
949 largest_changestamp));
953 metadata_store_->AddIncrementalSyncOrigin(origin, resource_id);
954 may_have_unfetched_changes_ = true;
955 callback.Run(SYNC_STATUS_OK);
958 void DriveFileSyncService::DidProcessRemoteChange(
959 const SyncFileCallback& sync_callback,
960 const SyncStatusCallback& completion_callback,
961 SyncStatusCode status) {
962 fileapi::FileSystemURL url;
963 if (running_remote_sync_task_)
964 url = running_remote_sync_task_->url();
965 running_remote_sync_task_.reset();
967 completion_callback.Run(status);
968 sync_callback.Run(status, url);
971 void DriveFileSyncService::DidApplyLocalChange(
972 const SyncStatusCallback& callback,
973 SyncStatusCode status) {
974 running_local_sync_task_.reset();
975 callback.Run(status);
978 bool DriveFileSyncService::AppendRemoteChange(
980 const google_apis::ResourceEntry& entry,
982 base::FilePath path = TitleToPath(entry.title());
984 if (!entry.is_folder() && !entry.is_file() && !entry.deleted())
987 if (entry.is_folder() && !IsSyncFSDirectoryOperationEnabled())
990 SyncFileType file_type = entry.is_file() ?
991 SYNC_FILE_TYPE_FILE : SYNC_FILE_TYPE_DIRECTORY;
993 return AppendRemoteChangeInternal(
994 origin, path, entry.deleted(),
995 entry.resource_id(), changestamp,
996 entry.deleted() ? std::string() : entry.file_md5(),
997 entry.updated_time(), file_type);
1000 bool DriveFileSyncService::AppendFetchChange(
1002 const base::FilePath& path,
1003 const std::string& resource_id,
1004 SyncFileType type) {
1005 return AppendRemoteChangeInternal(
1007 false, // is_deleted
1010 std::string(), // remote_file_md5
1011 base::Time(), // updated_time
1015 bool DriveFileSyncService::AppendRemoteChangeInternal(
1017 const base::FilePath& path,
1019 const std::string& remote_resource_id,
1021 const std::string& remote_file_md5,
1022 const base::Time& updated_time,
1023 SyncFileType file_type) {
1024 fileapi::FileSystemURL url(CreateSyncableFileSystemURL(origin, path));
1025 DCHECK(url.is_valid());
1027 // Note that we create a normalized path from url.path() rather than
1028 // path here (as FileSystemURL does extra normalization).
1029 base::FilePath::StringType normalized_path =
1030 fileapi::VirtualPath::GetNormalizedFilePath(url.path());
1032 std::string local_resource_id;
1033 std::string local_file_md5;
1035 DriveMetadata metadata;
1037 (metadata_store_->ReadEntry(url, &metadata) == SYNC_STATUS_OK);
1039 local_resource_id = metadata.resource_id();
1040 if (!metadata.to_be_fetched())
1041 local_file_md5 = metadata.md5_checksum();
1044 RemoteChangeHandler::RemoteChange pending_change;
1045 if (remote_change_handler_.GetChangeForURL(url, &pending_change)) {
1046 if (pending_change.changestamp >= changestamp)
1049 if (pending_change.change.IsDelete()) {
1050 local_resource_id.clear();
1051 local_file_md5.clear();
1053 local_resource_id = pending_change.resource_id;
1054 local_file_md5 = pending_change.md5_checksum;
1058 // Drop the change if remote update change does not change file content.
1059 if (!remote_file_md5.empty() &&
1060 !local_file_md5.empty() &&
1061 remote_file_md5 == local_file_md5)
1064 // Drop the change if remote change is for directory addition that is
1066 if (file_type == SYNC_FILE_TYPE_DIRECTORY &&
1068 !local_resource_id.empty() &&
1069 metadata.type() == DriveMetadata_ResourceType_RESOURCE_TYPE_FOLDER)
1072 // Drop any change if the change has unknown resource id.
1073 if (!remote_resource_id.empty() &&
1074 !local_resource_id.empty() &&
1075 remote_resource_id != local_resource_id)
1079 // Drop any change if the change is for deletion and local resource id is
1081 if (local_resource_id.empty())
1084 // Determine a file type of the deleted change by local metadata.
1085 if (!remote_resource_id.empty() &&
1086 !local_resource_id.empty() &&
1087 remote_resource_id == local_resource_id) {
1088 DCHECK(IsSyncFSDirectoryOperationEnabled() ||
1089 DriveMetadata::RESOURCE_TYPE_FILE == metadata.type());
1090 file_type = metadata.type() == DriveMetadata::RESOURCE_TYPE_FILE ?
1091 SYNC_FILE_TYPE_FILE : SYNC_FILE_TYPE_DIRECTORY;
1095 metadata.set_resource_id(std::string());
1096 metadata_store_->UpdateEntry(url, metadata,
1097 base::Bind(&EmptyStatusCallback));
1101 FileChange file_change(is_deleted ? FileChange::FILE_CHANGE_DELETE
1102 : FileChange::FILE_CHANGE_ADD_OR_UPDATE,
1105 RemoteChangeHandler::RemoteChange remote_change(
1106 changestamp, remote_resource_id, remote_file_md5,
1107 updated_time, url, file_change);
1108 remote_change_handler_.AppendChange(remote_change);
1110 DVLOG(3) << "Append remote change: " << path.value()
1111 << " (" << normalized_path << ")"
1112 << "@" << changestamp << " "
1113 << file_change.DebugString();
1118 void DriveFileSyncService::RemoveRemoteChange(
1119 const FileSystemURL& url) {
1120 remote_change_handler_.RemoveChangeForURL(url);
1123 void DriveFileSyncService::MarkConflict(
1124 const fileapi::FileSystemURL& url,
1125 DriveMetadata* drive_metadata,
1126 const SyncStatusCallback& callback) {
1127 DCHECK(drive_metadata);
1128 DCHECK(!drive_metadata->resource_id().empty());
1129 drive_metadata->set_conflicted(true);
1130 drive_metadata->set_to_be_fetched(false);
1131 metadata_store_->UpdateEntry(
1132 url, *drive_metadata, base::Bind(
1133 &DriveFileSyncService::NotifyConflict,
1134 AsWeakPtr(), url, callback));
1137 void DriveFileSyncService::NotifyConflict(
1138 const fileapi::FileSystemURL& url,
1139 const SyncStatusCallback& callback,
1140 SyncStatusCode status) {
1141 if (status != SYNC_STATUS_OK) {
1142 callback.Run(status);
1145 NotifyObserversFileStatusChanged(url,
1146 SYNC_FILE_STATUS_CONFLICTING,
1148 SYNC_DIRECTION_NONE);
1149 callback.Run(status);
1152 SyncStatusCode DriveFileSyncService::GDataErrorCodeToSyncStatusCodeWrapper(
1153 google_apis::GDataErrorCode error) {
1154 last_gdata_error_ = error;
1155 SyncStatusCode status = drive_backend::GDataErrorCodeToSyncStatusCode(error);
1156 if (status != SYNC_STATUS_OK && !api_util_->IsAuthenticated())
1157 return SYNC_STATUS_AUTHENTICATION_FAILED;
1161 void DriveFileSyncService::MaybeStartFetchChanges() {
1162 if (GetCurrentState() == REMOTE_SERVICE_DISABLED)
1165 // If we have pending_batch_sync_origins, try starting the batch sync.
1166 if (!pending_batch_sync_origins_.empty()) {
1167 if (GetCurrentState() == REMOTE_SERVICE_OK || may_have_unfetched_changes_) {
1168 task_manager_->ScheduleTaskIfIdle(
1169 base::Bind(&DriveFileSyncService::StartBatchSync, AsWeakPtr()),
1170 SyncStatusCallback());
1175 if (may_have_unfetched_changes_ &&
1176 !metadata_store_->incremental_sync_origins().empty()) {
1177 task_manager_->ScheduleTaskIfIdle(
1178 base::Bind(&DriveFileSyncService::FetchChangesForIncrementalSync,
1180 SyncStatusCallback());
1184 void DriveFileSyncService::OnNotificationReceived() {
1185 VLOG(2) << "Notification received to check for Google Drive updates";
1187 // Likely indicating the network is enabled again.
1188 UpdateServiceState(REMOTE_SERVICE_OK, "Got push notification for Drive.");
1190 // TODO(calvinlo): Try to eliminate may_have_unfetched_changes_ variable.
1191 may_have_unfetched_changes_ = true;
1192 MaybeStartFetchChanges();
1195 void DriveFileSyncService::OnPushNotificationEnabled(bool enabled) {
1196 VLOG(2) << "XMPP Push notification is " << (enabled ? "enabled" : "disabled");
1199 void DriveFileSyncService::MaybeScheduleNextTask() {
1200 if (GetCurrentState() == REMOTE_SERVICE_DISABLED)
1203 // Notify observer of the update of |pending_changes_|.
1204 FOR_EACH_OBSERVER(Observer, service_observers_,
1205 OnRemoteChangeQueueUpdated(
1206 remote_change_handler_.ChangesSize()));
1208 MaybeStartFetchChanges();
1211 void DriveFileSyncService::NotifyLastOperationStatus(
1212 SyncStatusCode sync_status,
1213 bool used_network) {
1214 UpdateServiceStateFromLastOperationStatus(sync_status, last_gdata_error_);
1218 std::string DriveFileSyncService::PathToTitle(const base::FilePath& path) {
1219 if (!IsSyncFSDirectoryOperationEnabled())
1220 return path.AsUTF8Unsafe();
1222 return fileapi::FilePathToString(
1223 base::FilePath(fileapi::VirtualPath::GetNormalizedFilePath(path)));
1227 base::FilePath DriveFileSyncService::TitleToPath(const std::string& title) {
1228 if (!IsSyncFSDirectoryOperationEnabled())
1229 return base::FilePath::FromUTF8Unsafe(title);
1231 return fileapi::StringToFilePath(title).NormalizePathSeparators();
1235 DriveMetadata::ResourceType
1236 DriveFileSyncService::SyncFileTypeToDriveMetadataResourceType(
1237 SyncFileType file_type) {
1238 DCHECK_NE(SYNC_FILE_TYPE_UNKNOWN, file_type);
1239 switch (file_type) {
1240 case SYNC_FILE_TYPE_UNKNOWN:
1241 return DriveMetadata_ResourceType_RESOURCE_TYPE_FILE;
1242 case SYNC_FILE_TYPE_FILE:
1243 return DriveMetadata_ResourceType_RESOURCE_TYPE_FILE;
1244 case SYNC_FILE_TYPE_DIRECTORY:
1245 return DriveMetadata_ResourceType_RESOURCE_TYPE_FOLDER;
1248 return DriveMetadata_ResourceType_RESOURCE_TYPE_FILE;
1252 SyncFileType DriveFileSyncService::DriveMetadataResourceTypeToSyncFileType(
1253 DriveMetadata::ResourceType resource_type) {
1254 switch (resource_type) {
1255 case DriveMetadata_ResourceType_RESOURCE_TYPE_FILE:
1256 return SYNC_FILE_TYPE_FILE;
1257 case DriveMetadata_ResourceType_RESOURCE_TYPE_FOLDER:
1258 return SYNC_FILE_TYPE_DIRECTORY;
1261 return SYNC_FILE_TYPE_UNKNOWN;
1264 void DriveFileSyncService::FetchChangesForIncrementalSync(
1265 const SyncStatusCallback& callback) {
1266 DCHECK(may_have_unfetched_changes_);
1267 DCHECK(pending_batch_sync_origins_.empty());
1268 DCHECK(!metadata_store_->incremental_sync_origins().empty());
1270 DVLOG(1) << "FetchChangesForIncrementalSync (start_changestamp:"
1271 << (largest_fetched_changestamp_ + 1) << ")";
1273 api_util_->ListChanges(
1274 largest_fetched_changestamp_ + 1,
1275 base::Bind(&DriveFileSyncService::DidFetchChangesForIncrementalSync,
1280 may_have_unfetched_changes_ = false;
1283 void DriveFileSyncService::DidFetchChangesForIncrementalSync(
1284 const SyncStatusCallback& callback,
1285 bool has_new_changes,
1286 google_apis::GDataErrorCode error,
1287 scoped_ptr<google_apis::ResourceList> changes) {
1288 if (error != google_apis::HTTP_SUCCESS) {
1289 callback.Run(GDataErrorCodeToSyncStatusCodeWrapper(error));
1293 bool reset_sync_root = false;
1294 std::set<GURL> reset_origins;
1296 typedef ScopedVector<google_apis::ResourceEntry>::const_iterator iterator;
1297 for (iterator itr = changes->entries().begin();
1298 itr != changes->entries().end(); ++itr) {
1299 const google_apis::ResourceEntry& entry = **itr;
1301 if (entry.deleted()) {
1302 // Check if the sync root or origin root folder is deleted.
1303 // (We reset resource_id after the for loop so that we can handle
1304 // recursive delete for the origin (at least in this feed)
1305 // while GetOriginForEntry for the origin still works.)
1306 if (entry.resource_id() == sync_root_resource_id()) {
1307 reset_sync_root = true;
1311 if (metadata_store_->GetOriginByOriginRootDirectoryId(
1312 entry.resource_id(), &origin)) {
1313 reset_origins.insert(origin);
1319 if (!GetOriginForEntry(entry, &origin))
1322 DVLOG(3) << " * change:" << entry.title()
1323 << (entry.deleted() ? " (deleted)" : " ")
1324 << "[" << origin.spec() << "]";
1325 has_new_changes = AppendRemoteChange(
1326 origin, entry, entry.changestamp()) || has_new_changes;
1329 if (reset_sync_root) {
1330 util::Log(logging::LOG_WARNING,
1332 "Detected unexpected SyncRoot deletion.");
1333 metadata_store_->SetSyncRootDirectory(std::string());
1335 for (std::set<GURL>::iterator itr = reset_origins.begin();
1336 itr != reset_origins.end(); ++itr) {
1337 util::Log(logging::LOG_WARNING,
1339 "Detected unexpected OriginRoot deletion: %s",
1340 itr->spec().c_str());
1341 pending_batch_sync_origins_.erase(*itr);
1342 metadata_store_->SetOriginRootDirectory(*itr, std::string());
1346 if (changes->GetNextFeedURL(&next_feed))
1347 may_have_unfetched_changes_ = true;
1349 if (!changes->entries().empty())
1350 largest_fetched_changestamp_ = changes->entries().back()->changestamp();
1352 callback.Run(SYNC_STATUS_OK);
1355 bool DriveFileSyncService::GetOriginForEntry(
1356 const google_apis::ResourceEntry& entry,
1358 typedef ScopedVector<google_apis::Link>::const_iterator iterator;
1359 for (iterator itr = entry.links().begin();
1360 itr != entry.links().end(); ++itr) {
1361 if ((*itr)->type() != google_apis::Link::LINK_PARENT)
1364 std::string resource_id(
1365 drive::util::ExtractResourceIdFromUrl((*itr)->href()));
1366 if (resource_id.empty())
1370 metadata_store_->GetOriginByOriginRootDirectoryId(resource_id, &origin);
1371 if (!origin.is_valid() || !metadata_store_->IsIncrementalSyncOrigin(origin))
1374 *origin_out = origin;
1380 void DriveFileSyncService::NotifyObserversFileStatusChanged(
1381 const FileSystemURL& url,
1382 SyncFileStatus sync_status,
1383 SyncAction action_taken,
1384 SyncDirection direction) {
1385 if (sync_status != SYNC_FILE_STATUS_SYNCED) {
1386 DCHECK_EQ(SYNC_ACTION_NONE, action_taken);
1387 DCHECK_EQ(SYNC_DIRECTION_NONE, direction);
1391 FileStatusObserver, file_status_observers_,
1392 OnFileStatusChanged(url, sync_status, action_taken, direction));
1395 void DriveFileSyncService::EnsureSyncRootDirectory(
1396 const ResourceIdCallback& callback) {
1397 if (!sync_root_resource_id().empty()) {
1398 callback.Run(SYNC_STATUS_OK, sync_root_resource_id());
1402 api_util_->GetDriveDirectoryForSyncRoot(base::Bind(
1403 &DriveFileSyncService::DidEnsureSyncRoot, AsWeakPtr(), callback));
1406 void DriveFileSyncService::DidEnsureSyncRoot(
1407 const ResourceIdCallback& callback,
1408 google_apis::GDataErrorCode error,
1409 const std::string& sync_root_resource_id) {
1410 SyncStatusCode status = GDataErrorCodeToSyncStatusCodeWrapper(error);
1411 if (status == SYNC_STATUS_OK)
1412 metadata_store_->SetSyncRootDirectory(sync_root_resource_id);
1413 callback.Run(status, sync_root_resource_id);
1416 void DriveFileSyncService::EnsureOriginRootDirectory(
1418 const ResourceIdCallback& callback) {
1419 std::string resource_id = metadata_store_->GetResourceIdForOrigin(origin);
1420 if (!resource_id.empty()) {
1421 callback.Run(SYNC_STATUS_OK, resource_id);
1425 EnsureSyncRootDirectory(base::Bind(
1426 &DriveFileSyncService::DidEnsureSyncRootForOriginRoot,
1427 AsWeakPtr(), origin, callback));
1430 void DriveFileSyncService::DidEnsureSyncRootForOriginRoot(
1432 const ResourceIdCallback& callback,
1433 SyncStatusCode status,
1434 const std::string& sync_root_resource_id) {
1435 if (status != SYNC_STATUS_OK) {
1436 callback.Run(status, std::string());
1440 api_util_->GetDriveDirectoryForOrigin(
1441 sync_root_resource_id,
1443 base::Bind(&DriveFileSyncService::DidEnsureOriginRoot,
1449 void DriveFileSyncService::DidEnsureOriginRoot(
1451 const ResourceIdCallback& callback,
1452 google_apis::GDataErrorCode error,
1453 const std::string& resource_id) {
1454 SyncStatusCode status = GDataErrorCodeToSyncStatusCodeWrapper(error);
1455 if (status == SYNC_STATUS_OK &&
1456 metadata_store_->IsKnownOrigin(origin)) {
1457 metadata_store_->SetOriginRootDirectory(origin, resource_id);
1459 callback.Run(status, resource_id);
1462 std::string DriveFileSyncService::sync_root_resource_id() {
1463 return metadata_store_->sync_root_directory();
1466 } // namespace sync_file_system