OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/sync_file_system/drive_file_sync_service.h" | 5 #include "chrome/browser/sync_file_system/drive_file_sync_service.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 #include <string> | 8 #include <string> |
9 #include <utility> | 9 #include <utility> |
10 | 10 |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
45 FILE_PATH_LITERAL("Sync FileSystem"); | 45 FILE_PATH_LITERAL("Sync FileSystem"); |
46 | 46 |
47 // The sync invalidation object ID for Google Drive. | 47 // The sync invalidation object ID for Google Drive. |
48 const char kDriveInvalidationObjectId[] = "CHANGELOG"; | 48 const char kDriveInvalidationObjectId[] = "CHANGELOG"; |
49 | 49 |
50 // Incremental sync polling interval. | 50 // Incremental sync polling interval. |
51 // TODO(calvinlo): Improve polling algorithm dependent on whether push | 51 // TODO(calvinlo): Improve polling algorithm dependent on whether push |
52 // notifications are on or off. | 52 // notifications are on or off. |
53 const int64 kMinimumPollingDelaySeconds = 5; | 53 const int64 kMinimumPollingDelaySeconds = 5; |
54 const int64 kMaximumPollingDelaySeconds = 10 * 60; // 10 min | 54 const int64 kMaximumPollingDelaySeconds = 10 * 60; // 10 min |
55 const int64 kPollingDelaySecondsWithNotification = 4 * 60 * 60; // 4 hr | 55 const int64 kPollingDelaySecondsWithNotification = 10 * 60; // 10 min |
56 const double kDelayMultiplier = 1.6; | 56 const double kDelayMultiplier = 1.6; |
57 | 57 |
58 bool CreateTemporaryFile(const FilePath& dir_path, FilePath* temp_file) { | 58 bool CreateTemporaryFile(const FilePath& dir_path, FilePath* temp_file) { |
59 return file_util::CreateDirectory(dir_path) && | 59 return file_util::CreateDirectory(dir_path) && |
60 file_util::CreateTemporaryFileInDir(dir_path, temp_file); | 60 file_util::CreateTemporaryFileInDir(dir_path, temp_file); |
61 } | 61 } |
62 | 62 |
63 void DeleteTemporaryFile(const FilePath& file_path) { | 63 void DeleteTemporaryFile(const FilePath& file_path) { |
64 if (!content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE)) { | 64 if (!content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE)) { |
65 content::BrowserThread::PostTask( | 65 content::BrowserThread::PostTask( |
66 content::BrowserThread::FILE, FROM_HERE, | 66 content::BrowserThread::FILE, FROM_HERE, |
67 base::Bind(&DeleteTemporaryFile, file_path)); | 67 base::Bind(&DeleteTemporaryFile, file_path)); |
68 return; | 68 return; |
69 } | 69 } |
70 | 70 |
71 if (!file_util::Delete(file_path, true)) | 71 if (!file_util::Delete(file_path, true)) |
72 LOG(ERROR) << "Leaked temporary file for Sync FileSystem: " | 72 LOG(ERROR) << "Leaked temporary file for Sync FileSystem: " |
73 << file_path.value(); | 73 << file_path.value(); |
74 } | 74 } |
75 | 75 |
76 void EmptyStatusCallback(fileapi::SyncStatusCode code) {} | 76 void EmptyStatusCallback(fileapi::SyncStatusCode code) {} |
77 | 77 |
78 void MarkFetchingChangesCompleted(bool* is_fetching_changes) { | |
79 *is_fetching_changes = false; | |
80 } | |
81 | |
82 void DidRemoveOrigin(const GURL& origin, fileapi::SyncStatusCode status) { | 78 void DidRemoveOrigin(const GURL& origin, fileapi::SyncStatusCode status) { |
83 // TODO(calvinlo): Disable syncing if status not ok (http://crbug.com/171611). | 79 // TODO(calvinlo): Disable syncing if status not ok (http://crbug.com/171611). |
84 DCHECK_EQ(fileapi::SYNC_STATUS_OK, status); | 80 DCHECK_EQ(fileapi::SYNC_STATUS_OK, status); |
85 LOG(WARNING) << "Remove origin failed for: " << origin.spec() | 81 LOG(WARNING) << "Remove origin failed for: " << origin.spec() |
86 << " status=" << status; | 82 << " status=" << status; |
87 } | 83 } |
88 | 84 |
89 fileapi::FileChange CreateFileChange(bool is_deleted) { | 85 fileapi::FileChange CreateFileChange(bool is_deleted) { |
90 if (is_deleted) { | 86 if (is_deleted) { |
91 return fileapi::FileChange(fileapi::FileChange::FILE_CHANGE_DELETE, | 87 return fileapi::FileChange(fileapi::FileChange::FILE_CHANGE_DELETE, |
(...skipping 11 matching lines...) Expand all Loading... |
103 public: | 99 public: |
104 explicit TaskToken(const base::WeakPtr<DriveFileSyncService>& sync_service) | 100 explicit TaskToken(const base::WeakPtr<DriveFileSyncService>& sync_service) |
105 : sync_service_(sync_service), | 101 : sync_service_(sync_service), |
106 task_type_(TASK_TYPE_NONE) { | 102 task_type_(TASK_TYPE_NONE) { |
107 } | 103 } |
108 | 104 |
109 void ResetTask(const tracked_objects::Location& location) { | 105 void ResetTask(const tracked_objects::Location& location) { |
110 location_ = location; | 106 location_ = location; |
111 task_type_ = TASK_TYPE_NONE; | 107 task_type_ = TASK_TYPE_NONE; |
112 description_.clear(); | 108 description_.clear(); |
113 if (!completion_callback_.is_null()) | |
114 completion_callback_.Run(); | |
115 completion_callback_.Reset(); | |
116 } | 109 } |
117 | 110 |
118 void UpdateTask(const tracked_objects::Location& location, | 111 void UpdateTask(const tracked_objects::Location& location, |
119 TaskType task_type, | 112 TaskType task_type, |
120 const std::string& description) { | 113 const std::string& description) { |
121 location_ = location; | 114 location_ = location; |
122 task_type_ = task_type; | 115 task_type_ = task_type; |
123 description_ = description; | 116 description_ = description; |
124 | 117 |
125 DVLOG(2) << "Token updated: " << description_ | 118 DVLOG(2) << "Token updated: " << description_ |
126 << " " << location_.ToString(); | 119 << " " << location_.ToString(); |
127 } | 120 } |
128 | 121 |
129 const tracked_objects::Location& location() const { return location_; } | 122 const tracked_objects::Location& location() const { return location_; } |
130 TaskType task_type() const { return task_type_; } | 123 TaskType task_type() const { return task_type_; } |
131 const std::string& description() const { return description_; } | 124 const std::string& description() const { return description_; } |
132 std::string done_description() const { return description_ + " done"; } | 125 std::string done_description() const { return description_ + " done"; } |
133 | 126 |
134 void set_completion_callback(const base::Closure& callback) { | |
135 completion_callback_ = callback; | |
136 } | |
137 | |
138 const base::Closure& completion_callback() { | |
139 return completion_callback_; | |
140 } | |
141 | |
142 ~TaskToken() { | 127 ~TaskToken() { |
143 // All task on DriveFileSyncService must hold TaskToken instance to ensure | 128 // All task on DriveFileSyncService must hold TaskToken instance to ensure |
144 // no other tasks are running. Also, as soon as a task finishes to work, | 129 // no other tasks are running. Also, as soon as a task finishes to work, |
145 // it must return the token to DriveFileSyncService. | 130 // it must return the token to DriveFileSyncService. |
146 // Destroying a token with valid |sync_service_| indicates the token was | 131 // Destroying a token with valid |sync_service_| indicates the token was |
147 // dropped by a task without returning. | 132 // dropped by a task without returning. |
148 if (sync_service_) { | 133 if (sync_service_) { |
149 LOG(ERROR) << "Unexpected TaskToken deletion from: " | 134 LOG(ERROR) << "Unexpected TaskToken deletion from: " |
150 << location_.ToString() << " while: " << description_; | 135 << location_.ToString() << " while: " << description_; |
151 } | 136 } |
152 DCHECK(!sync_service_); | 137 DCHECK(!sync_service_); |
153 } | 138 } |
154 | 139 |
155 private: | 140 private: |
156 base::WeakPtr<DriveFileSyncService> sync_service_; | 141 base::WeakPtr<DriveFileSyncService> sync_service_; |
157 tracked_objects::Location location_; | 142 tracked_objects::Location location_; |
158 TaskType task_type_; | 143 TaskType task_type_; |
159 std::string description_; | 144 std::string description_; |
160 base::Closure completion_callback_; | |
161 | 145 |
162 DISALLOW_COPY_AND_ASSIGN(TaskToken); | 146 DISALLOW_COPY_AND_ASSIGN(TaskToken); |
163 }; | 147 }; |
164 | 148 |
165 void DriveFileSyncService::OnInvalidatorStateChange( | 149 void DriveFileSyncService::OnInvalidatorStateChange( |
166 syncer::InvalidatorState state) { | 150 syncer::InvalidatorState state) { |
167 SetPushNotificationEnabled(state); | 151 SetPushNotificationEnabled(state); |
168 } | 152 } |
169 | 153 |
170 void DriveFileSyncService::SetPushNotificationEnabled( | 154 void DriveFileSyncService::SetPushNotificationEnabled( |
171 syncer::InvalidatorState state) { | 155 syncer::InvalidatorState state) { |
172 push_notification_enabled_ = (state == syncer::INVALIDATIONS_ENABLED); | 156 push_notification_enabled_ = (state == syncer::INVALIDATIONS_ENABLED); |
173 if (!push_notification_enabled_) | 157 if (!push_notification_enabled_) |
174 return; | 158 return; |
175 | 159 |
176 // Push notifications are enabled so reset polling timer. | 160 // Push notifications are enabled so reset polling timer. |
177 UpdatePollingDelay(kPollingDelaySecondsWithNotification); | 161 UpdatePollingDelay(kPollingDelaySecondsWithNotification); |
178 } | 162 } |
179 | 163 |
180 void DriveFileSyncService::OnIncomingInvalidation( | 164 void DriveFileSyncService::OnIncomingInvalidation( |
181 const syncer::ObjectIdInvalidationMap& invalidation_map) { | 165 const syncer::ObjectIdInvalidationMap& invalidation_map) { |
182 DCHECK(push_notification_enabled_); | 166 DCHECK(push_notification_enabled_); |
183 DCHECK_EQ(1U, invalidation_map.size()); | 167 DCHECK_EQ(1U, invalidation_map.size()); |
184 const invalidation::ObjectId object_id( | 168 const invalidation::ObjectId object_id( |
185 ipc::invalidation::ObjectSource::COSMO_CHANGELOG, | 169 ipc::invalidation::ObjectSource::COSMO_CHANGELOG, |
186 kDriveInvalidationObjectId); | 170 kDriveInvalidationObjectId); |
187 DCHECK_EQ(1U, invalidation_map.count(object_id)); | 171 DCHECK_EQ(1U, invalidation_map.count(object_id)); |
188 | 172 |
| 173 has_unfetched_remote_change_ = true; |
189 FetchChangesForIncrementalSync(); | 174 FetchChangesForIncrementalSync(); |
190 } | 175 } |
191 | 176 |
192 struct DriveFileSyncService::ProcessRemoteChangeParam { | 177 struct DriveFileSyncService::ProcessRemoteChangeParam { |
193 scoped_ptr<TaskToken> token; | 178 scoped_ptr<TaskToken> token; |
194 RemoteChangeProcessor* processor; | 179 RemoteChangeProcessor* processor; |
195 RemoteChange remote_change; | 180 RemoteChange remote_change; |
196 fileapi::SyncFileCallback callback; | 181 fileapi::SyncFileCallback callback; |
197 | 182 |
198 DriveMetadata drive_metadata; | 183 DriveMetadata drive_metadata; |
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
280 | 265 |
281 DriveFileSyncService::DriveFileSyncService(Profile* profile) | 266 DriveFileSyncService::DriveFileSyncService(Profile* profile) |
282 : profile_(profile), | 267 : profile_(profile), |
283 last_operation_status_(fileapi::SYNC_STATUS_OK), | 268 last_operation_status_(fileapi::SYNC_STATUS_OK), |
284 state_(REMOTE_SERVICE_OK), | 269 state_(REMOTE_SERVICE_OK), |
285 sync_enabled_(true), | 270 sync_enabled_(true), |
286 largest_fetched_changestamp_(0), | 271 largest_fetched_changestamp_(0), |
287 push_notification_registered_(false), | 272 push_notification_registered_(false), |
288 push_notification_enabled_(false), | 273 push_notification_enabled_(false), |
289 polling_delay_seconds_(kMinimumPollingDelaySeconds), | 274 polling_delay_seconds_(kMinimumPollingDelaySeconds), |
290 is_fetching_changes_(false), | 275 has_unfetched_remote_change_(true), |
291 weak_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) { | 276 weak_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) { |
292 temporary_file_dir_ = | 277 temporary_file_dir_ = |
293 profile->GetPath().Append(kSyncFileSystemDir).Append(kTempDirName); | 278 profile->GetPath().Append(kSyncFileSystemDir).Append(kTempDirName); |
294 token_.reset(new TaskToken(AsWeakPtr())); | 279 token_.reset(new TaskToken(AsWeakPtr())); |
295 | 280 |
296 sync_client_.reset(new DriveFileSyncClient(profile)); | 281 sync_client_.reset(new DriveFileSyncClient(profile)); |
297 sync_client_->AddObserver(this); | 282 sync_client_->AddObserver(this); |
298 | 283 |
299 metadata_store_.reset(new DriveMetadataStore( | 284 metadata_store_.reset(new DriveMetadataStore( |
300 profile->GetPath().Append(kSyncFileSystemDir), | 285 profile->GetPath().Append(kSyncFileSystemDir), |
(...skipping 399 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
700 scoped_ptr<DriveFileSyncClient> sync_client, | 685 scoped_ptr<DriveFileSyncClient> sync_client, |
701 scoped_ptr<DriveMetadataStore> metadata_store) | 686 scoped_ptr<DriveMetadataStore> metadata_store) |
702 : profile_(profile), | 687 : profile_(profile), |
703 last_operation_status_(fileapi::SYNC_STATUS_OK), | 688 last_operation_status_(fileapi::SYNC_STATUS_OK), |
704 state_(REMOTE_SERVICE_OK), | 689 state_(REMOTE_SERVICE_OK), |
705 sync_enabled_(true), | 690 sync_enabled_(true), |
706 largest_fetched_changestamp_(0), | 691 largest_fetched_changestamp_(0), |
707 push_notification_registered_(false), | 692 push_notification_registered_(false), |
708 push_notification_enabled_(false), | 693 push_notification_enabled_(false), |
709 polling_delay_seconds_(-1), | 694 polling_delay_seconds_(-1), |
710 is_fetching_changes_(false), | 695 has_unfetched_remote_change_(true), |
711 weak_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) { | 696 weak_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) { |
712 DCHECK(profile); | 697 DCHECK(profile); |
713 temporary_file_dir_ = base_dir.Append(kTempDirName); | 698 temporary_file_dir_ = base_dir.Append(kTempDirName); |
714 | 699 |
715 token_.reset(new TaskToken(AsWeakPtr())); | 700 token_.reset(new TaskToken(AsWeakPtr())); |
716 sync_client_ = sync_client.Pass(); | 701 sync_client_ = sync_client.Pass(); |
717 metadata_store_ = metadata_store.Pass(); | 702 metadata_store_ = metadata_store.Pass(); |
718 | 703 |
719 base::MessageLoopProxy::current()->PostTask( | 704 base::MessageLoopProxy::current()->PostTask( |
720 FROM_HERE, | 705 FROM_HERE, |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
760 | 745 |
761 // Notify remote sync service state if the state has been changed. | 746 // Notify remote sync service state if the state has been changed. |
762 if (!token_->description().empty() || old_state != GetCurrentState()) { | 747 if (!token_->description().empty() || old_state != GetCurrentState()) { |
763 FOR_EACH_OBSERVER( | 748 FOR_EACH_OBSERVER( |
764 Observer, service_observers_, | 749 Observer, service_observers_, |
765 OnRemoteServiceStateUpdated(GetCurrentState(), | 750 OnRemoteServiceStateUpdated(GetCurrentState(), |
766 token_->done_description())); | 751 token_->done_description())); |
767 } | 752 } |
768 } | 753 } |
769 | 754 |
770 if (!token_->completion_callback().is_null()) | |
771 token_->completion_callback().Run(); | |
772 | |
773 token_->ResetTask(FROM_HERE); | 755 token_->ResetTask(FROM_HERE); |
774 if (!pending_tasks_.empty()) { | 756 if (!pending_tasks_.empty()) { |
775 base::Closure closure = pending_tasks_.front(); | 757 base::Closure closure = pending_tasks_.front(); |
776 pending_tasks_.pop_front(); | 758 pending_tasks_.pop_front(); |
777 closure.Run(); | 759 closure.Run(); |
778 return; | 760 return; |
779 } | 761 } |
780 | 762 |
| 763 if (has_unfetched_remote_change_ && push_notification_enabled_) { |
| 764 FetchChangesForIncrementalSync(); |
| 765 return; |
| 766 } |
| 767 |
781 SchedulePolling(); | 768 SchedulePolling(); |
782 | 769 |
783 if (GetCurrentState() != REMOTE_SERVICE_OK && | 770 if (GetCurrentState() != REMOTE_SERVICE_OK) |
784 GetCurrentState() != REMOTE_SERVICE_TEMPORARY_UNAVAILABLE) | |
785 return; | 771 return; |
786 | 772 |
787 // If the state has become OK or TEMPORARY_UNAVAILABLE and we have any | 773 // If the state has become OK or TEMPORARY_UNAVAILABLE and we have any |
788 // pending batch sync origins, restart batch sync for them. | 774 // pending batch sync origins, restart batch sync for them. |
789 if (!pending_batch_sync_origins_.empty()) { | 775 if (!pending_batch_sync_origins_.empty()) { |
790 GURL origin = *pending_batch_sync_origins_.begin(); | 776 GURL origin = *pending_batch_sync_origins_.begin(); |
791 pending_batch_sync_origins_.erase(pending_batch_sync_origins_.begin()); | 777 pending_batch_sync_origins_.erase(pending_batch_sync_origins_.begin()); |
792 std::string resource_id = metadata_store_->GetResourceIdForOrigin(origin); | 778 std::string resource_id = metadata_store_->GetResourceIdForOrigin(origin); |
793 StartBatchSyncForOrigin(origin, resource_id); | 779 StartBatchSyncForOrigin(origin, resource_id); |
794 return; | 780 return; |
(...skipping 1035 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1830 return false; | 1816 return false; |
1831 const PathToChangeMap& path_to_change = found_url->second; | 1817 const PathToChangeMap& path_to_change = found_url->second; |
1832 PathToChangeMap::const_iterator found_path = path_to_change.find(url.path()); | 1818 PathToChangeMap::const_iterator found_path = path_to_change.find(url.path()); |
1833 if (found_path == path_to_change.end()) | 1819 if (found_path == path_to_change.end()) |
1834 return false; | 1820 return false; |
1835 *change = found_path->second; | 1821 *change = found_path->second; |
1836 return true; | 1822 return true; |
1837 } | 1823 } |
1838 | 1824 |
1839 void DriveFileSyncService::FetchChangesForIncrementalSync() { | 1825 void DriveFileSyncService::FetchChangesForIncrementalSync() { |
| 1826 if (!sync_enabled_ || |
| 1827 !pending_batch_sync_origins_.empty() || |
| 1828 metadata_store_->incremental_sync_origins().empty() || |
| 1829 !pending_changes_.empty()) |
| 1830 return; |
| 1831 |
1840 scoped_ptr<TaskToken> token(GetToken(FROM_HERE, TASK_TYPE_DRIVE, | 1832 scoped_ptr<TaskToken> token(GetToken(FROM_HERE, TASK_TYPE_DRIVE, |
1841 "Fetching remote change list")); | 1833 "Fetching remote change list")); |
1842 // If we got |token| successfully, |is_fetching_changes_| should be false. | 1834 if (!token) |
1843 // |is_fetching_changes_| is true only when the FetchChanges sequence is | |
1844 // running or is in |pending_queue_|. In both case, the token is owned by | |
1845 // the FetchChanges sequence. | |
1846 DCHECK(!token || !is_fetching_changes_); | |
1847 | |
1848 if (!sync_enabled_ || | |
1849 is_fetching_changes_ || | |
1850 !pending_batch_sync_origins_.empty() || | |
1851 metadata_store_->incremental_sync_origins().empty() || | |
1852 !pending_changes_.empty()) { | |
1853 if (token) { | |
1854 token->ResetTask(FROM_HERE); | |
1855 NotifyTaskDone(last_operation_status_, token.Pass()); | |
1856 } | |
1857 return; | 1835 return; |
1858 } | 1836 has_unfetched_remote_change_ = false; |
1859 | |
1860 is_fetching_changes_ = true; | |
1861 | |
1862 if (!token) { | |
1863 pending_tasks_.push_back(base::Bind( | |
1864 &DriveFileSyncService::FetchChangesForIncrementalSync, AsWeakPtr())); | |
1865 return; | |
1866 } | |
1867 | |
1868 token->set_completion_callback( | |
1869 base::Bind(&MarkFetchingChangesCompleted, &is_fetching_changes_)); | |
1870 | |
1871 if (metadata_store_->incremental_sync_origins().empty()) { | |
1872 token->ResetTask(FROM_HERE); | |
1873 NotifyTaskDone(fileapi::SYNC_STATUS_OK, token.Pass()); | |
1874 return; | |
1875 } | |
1876 | 1837 |
1877 DVLOG(1) << "FetchChangesForIncrementalSync (start_changestamp:" | 1838 DVLOG(1) << "FetchChangesForIncrementalSync (start_changestamp:" |
1878 << (largest_fetched_changestamp_ + 1) << ")"; | 1839 << (largest_fetched_changestamp_ + 1) << ")"; |
1879 | 1840 |
1880 sync_client_->ListChanges( | 1841 sync_client_->ListChanges( |
1881 largest_fetched_changestamp_ + 1, | 1842 largest_fetched_changestamp_ + 1, |
1882 base::Bind(&DriveFileSyncService::DidFetchChangesForIncrementalSync, | 1843 base::Bind(&DriveFileSyncService::DidFetchChangesForIncrementalSync, |
1883 AsWeakPtr(), base::Passed(&token), false)); | 1844 AsWeakPtr(), base::Passed(&token), false)); |
1884 } | 1845 } |
1885 | 1846 |
(...skipping 146 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2032 fileapi::SyncStatusCode | 1993 fileapi::SyncStatusCode |
2033 DriveFileSyncService::GDataErrorCodeToSyncStatusCodeWrapper( | 1994 DriveFileSyncService::GDataErrorCodeToSyncStatusCodeWrapper( |
2034 google_apis::GDataErrorCode error) const { | 1995 google_apis::GDataErrorCode error) const { |
2035 fileapi::SyncStatusCode status = GDataErrorCodeToSyncStatusCode(error); | 1996 fileapi::SyncStatusCode status = GDataErrorCodeToSyncStatusCode(error); |
2036 if (status != fileapi::SYNC_STATUS_OK && !sync_client_->IsAuthenticated()) | 1997 if (status != fileapi::SYNC_STATUS_OK && !sync_client_->IsAuthenticated()) |
2037 return fileapi::SYNC_STATUS_AUTHENTICATION_FAILED; | 1998 return fileapi::SYNC_STATUS_AUTHENTICATION_FAILED; |
2038 return status; | 1999 return status; |
2039 } | 2000 } |
2040 | 2001 |
2041 } // namespace sync_file_system | 2002 } // namespace sync_file_system |
OLD | NEW |