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/local/sync_file_system_backend.h"
9 #include "base/logging.h"
10 #include "chrome/browser/chrome_notification_types.h"
11 #include "chrome/browser/sync_file_system/local/local_file_change_tracker.h"
12 #include "chrome/browser/sync_file_system/local/local_file_sync_context.h"
13 #include "chrome/browser/sync_file_system/local/syncable_file_system_operation.h"
14 #include "chrome/browser/sync_file_system/sync_file_system_service.h"
15 #include "chrome/browser/sync_file_system/sync_file_system_service_factory.h"
16 #include "chrome/browser/sync_file_system/syncable_file_system_util.h"
17 #include "content/public/browser/browser_thread.h"
18 #include "content/public/browser/notification_service.h"
19 #include "storage/browser/blob/file_stream_reader.h"
20 #include "storage/browser/fileapi/file_stream_writer.h"
21 #include "storage/browser/fileapi/file_system_context.h"
22 #include "storage/browser/fileapi/file_system_operation.h"
23 #include "storage/common/fileapi/file_system_util.h"
25 using content::BrowserThread
;
27 namespace sync_file_system
{
31 bool CalledOnUIThread() {
32 // Ensure that these methods are called on the UI thread, except for unittests
33 // where a UI thread might not have been created.
34 return BrowserThread::CurrentlyOn(BrowserThread::UI
) ||
35 !BrowserThread::IsMessageLoopValid(BrowserThread::UI
);
40 SyncFileSystemBackend::ProfileHolder::ProfileHolder(Profile
* profile
)
42 DCHECK(CalledOnUIThread());
44 chrome::NOTIFICATION_PROFILE_DESTROYED
,
45 content::Source
<Profile
>(profile_
));
48 void SyncFileSystemBackend::ProfileHolder::Observe(
50 const content::NotificationSource
& source
,
51 const content::NotificationDetails
& details
) {
52 DCHECK(CalledOnUIThread());
53 DCHECK_EQ(chrome::NOTIFICATION_PROFILE_DESTROYED
, type
);
54 DCHECK_EQ(profile_
, content::Source
<Profile
>(source
).ptr());
56 registrar_
.RemoveAll();
59 Profile
* SyncFileSystemBackend::ProfileHolder::GetProfile() {
60 DCHECK(CalledOnUIThread());
64 SyncFileSystemBackend::SyncFileSystemBackend(Profile
* profile
)
66 skip_initialize_syncfs_service_for_testing_(false) {
67 DCHECK(CalledOnUIThread());
69 profile_holder_
.reset(new ProfileHolder(profile
));
71 // Register the service name here to enable to crack an URL on SyncFileSystem
72 // even if SyncFileSystemService has not started yet.
73 RegisterSyncableFileSystem();
76 SyncFileSystemBackend::~SyncFileSystemBackend() {
77 if (change_tracker_
) {
78 GetDelegate()->file_task_runner()->DeleteSoon(
79 FROM_HERE
, change_tracker_
.release());
82 if (profile_holder_
&& !CalledOnUIThread()) {
83 BrowserThread::DeleteSoon(
84 BrowserThread::UI
, FROM_HERE
, profile_holder_
.release());
89 SyncFileSystemBackend
* SyncFileSystemBackend::CreateForTesting() {
90 DCHECK(CalledOnUIThread());
91 SyncFileSystemBackend
* backend
= new SyncFileSystemBackend(nullptr);
92 backend
->skip_initialize_syncfs_service_for_testing_
= true;
96 bool SyncFileSystemBackend::CanHandleType(storage::FileSystemType type
) const {
97 return type
== storage::kFileSystemTypeSyncable
||
98 type
== storage::kFileSystemTypeSyncableForInternalSync
;
101 void SyncFileSystemBackend::Initialize(storage::FileSystemContext
* context
) {
106 storage::SandboxFileSystemBackendDelegate
* delegate
= GetDelegate();
107 delegate
->RegisterQuotaUpdateObserver(storage::kFileSystemTypeSyncable
);
108 delegate
->RegisterQuotaUpdateObserver(
109 storage::kFileSystemTypeSyncableForInternalSync
);
112 void SyncFileSystemBackend::ResolveURL(const storage::FileSystemURL
& url
,
113 storage::OpenFileSystemMode mode
,
114 const OpenFileSystemCallback
& callback
) {
115 DCHECK(CanHandleType(url
.type()));
117 if (skip_initialize_syncfs_service_for_testing_
) {
118 GetDelegate()->OpenFileSystem(url
.origin(),
122 GetSyncableFileSystemRootURI(url
.origin()));
126 // It is safe to pass Unretained(this) since |context_| owns it.
127 SyncStatusCallback initialize_callback
=
128 base::Bind(&SyncFileSystemBackend::DidInitializeSyncFileSystemService
,
129 base::Unretained(this),
130 make_scoped_refptr(context_
),
135 InitializeSyncFileSystemService(url
.origin(), initialize_callback
);
138 storage::AsyncFileUtil
* SyncFileSystemBackend::GetAsyncFileUtil(
139 storage::FileSystemType type
) {
140 return GetDelegate()->file_util();
143 storage::WatcherManager
* SyncFileSystemBackend::GetWatcherManager(
144 storage::FileSystemType type
) {
148 storage::CopyOrMoveFileValidatorFactory
*
149 SyncFileSystemBackend::GetCopyOrMoveFileValidatorFactory(
150 storage::FileSystemType type
,
151 base::File::Error
* error_code
) {
153 *error_code
= base::File::FILE_OK
;
157 storage::FileSystemOperation
* SyncFileSystemBackend::CreateFileSystemOperation(
158 const storage::FileSystemURL
& url
,
159 storage::FileSystemContext
* context
,
160 base::File::Error
* error_code
) const {
161 DCHECK(CanHandleType(url
.type()));
165 scoped_ptr
<storage::FileSystemOperationContext
> operation_context
=
166 GetDelegate()->CreateFileSystemOperationContext(url
, context
, error_code
);
167 if (!operation_context
)
170 if (url
.type() == storage::kFileSystemTypeSyncableForInternalSync
) {
171 return storage::FileSystemOperation::Create(
172 url
, context
, operation_context
.Pass());
175 return new SyncableFileSystemOperation(
176 url
, context
, operation_context
.Pass());
179 bool SyncFileSystemBackend::SupportsStreaming(
180 const storage::FileSystemURL
& url
) const {
184 bool SyncFileSystemBackend::HasInplaceCopyImplementation(
185 storage::FileSystemType type
) const {
189 scoped_ptr
<storage::FileStreamReader
>
190 SyncFileSystemBackend::CreateFileStreamReader(
191 const storage::FileSystemURL
& url
,
193 int64 max_bytes_to_read
,
194 const base::Time
& expected_modification_time
,
195 storage::FileSystemContext
* context
) const {
196 DCHECK(CanHandleType(url
.type()));
197 return GetDelegate()->CreateFileStreamReader(
198 url
, offset
, expected_modification_time
, context
);
201 scoped_ptr
<storage::FileStreamWriter
>
202 SyncFileSystemBackend::CreateFileStreamWriter(
203 const storage::FileSystemURL
& url
,
205 storage::FileSystemContext
* context
) const {
206 DCHECK(CanHandleType(url
.type()));
207 return GetDelegate()->CreateFileStreamWriter(
208 url
, offset
, context
, storage::kFileSystemTypeSyncableForInternalSync
);
211 storage::FileSystemQuotaUtil
* SyncFileSystemBackend::GetQuotaUtil() {
212 return GetDelegate();
215 const storage::UpdateObserverList
* SyncFileSystemBackend::GetUpdateObservers(
216 storage::FileSystemType type
) const {
217 return GetDelegate()->GetUpdateObservers(type
);
220 const storage::ChangeObserverList
* SyncFileSystemBackend::GetChangeObservers(
221 storage::FileSystemType type
) const {
222 return GetDelegate()->GetChangeObservers(type
);
225 const storage::AccessObserverList
* SyncFileSystemBackend::GetAccessObservers(
226 storage::FileSystemType type
) const {
227 return GetDelegate()->GetAccessObservers(type
);
231 SyncFileSystemBackend
* SyncFileSystemBackend::GetBackend(
232 const storage::FileSystemContext
* file_system_context
) {
233 DCHECK(file_system_context
);
234 return static_cast<SyncFileSystemBackend
*>(
235 file_system_context
->GetFileSystemBackend(
236 storage::kFileSystemTypeSyncable
));
239 void SyncFileSystemBackend::SetLocalFileChangeTracker(
240 scoped_ptr
<LocalFileChangeTracker
> tracker
) {
241 DCHECK(!change_tracker_
);
243 change_tracker_
= tracker
.Pass();
245 storage::SandboxFileSystemBackendDelegate
* delegate
= GetDelegate();
246 delegate
->AddFileUpdateObserver(storage::kFileSystemTypeSyncable
,
247 change_tracker_
.get(),
248 delegate
->file_task_runner());
249 delegate
->AddFileChangeObserver(storage::kFileSystemTypeSyncable
,
250 change_tracker_
.get(),
251 delegate
->file_task_runner());
254 void SyncFileSystemBackend::set_sync_context(
255 LocalFileSyncContext
* sync_context
) {
256 DCHECK(!sync_context_
.get());
257 sync_context_
= sync_context
;
260 storage::SandboxFileSystemBackendDelegate
* SyncFileSystemBackend::GetDelegate()
263 DCHECK(context_
->sandbox_delegate());
264 return context_
->sandbox_delegate();
267 void SyncFileSystemBackend::InitializeSyncFileSystemService(
268 const GURL
& origin_url
,
269 const SyncStatusCallback
& callback
) {
270 // Repost to switch from IO thread to UI thread.
271 if (!BrowserThread::CurrentlyOn(BrowserThread::UI
)) {
272 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
273 // It is safe to pass Unretained(this) (see comments in OpenFileSystem()).
274 BrowserThread::PostTask(
275 BrowserThread::UI
, FROM_HERE
,
276 base::Bind(&SyncFileSystemBackend::InitializeSyncFileSystemService
,
277 base::Unretained(this), origin_url
, callback
));
281 if (!profile_holder_
->GetProfile()) {
282 // Profile was destroyed.
283 callback
.Run(SYNC_FILE_ERROR_FAILED
);
287 SyncFileSystemService
* service
= SyncFileSystemServiceFactory::GetForProfile(
288 profile_holder_
->GetProfile());
290 service
->InitializeForApp(context_
, origin_url
, callback
);
293 void SyncFileSystemBackend::DidInitializeSyncFileSystemService(
294 storage::FileSystemContext
* context
,
295 const GURL
& origin_url
,
296 storage::FileSystemType type
,
297 storage::OpenFileSystemMode mode
,
298 const OpenFileSystemCallback
& callback
,
299 SyncStatusCode status
) {
300 // Repost to switch from UI thread to IO thread.
301 if (!BrowserThread::CurrentlyOn(BrowserThread::IO
)) {
302 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
303 // It is safe to pass Unretained(this) since |context| owns it.
304 BrowserThread::PostTask(
305 BrowserThread::IO
, FROM_HERE
,
306 base::Bind(&SyncFileSystemBackend::DidInitializeSyncFileSystemService
,
307 base::Unretained(this), make_scoped_refptr(context
),
308 origin_url
, type
, mode
, callback
, status
));
312 if (status
!= sync_file_system::SYNC_STATUS_OK
) {
313 callback
.Run(GURL(), std::string(),
314 SyncStatusCodeToFileError(status
));
318 callback
.Run(GetSyncableFileSystemRootURI(origin_url
),
319 GetFileSystemName(origin_url
, type
),
320 base::File::FILE_OK
);
323 } // namespace sync_file_system