Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(361)

Side by Side Diff: chrome/browser/sync_file_system/drive_backend/drive_file_sync_service.cc

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

Powered by Google App Engine
This is Rietveld 408576698