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"
7 #include "base/logging.h"
8 #include "chrome/browser/chrome_notification_types.h"
9 #include "chrome/browser/sync_file_system/local/local_file_change_tracker.h"
10 #include "chrome/browser/sync_file_system/local/local_file_sync_context.h"
11 #include "chrome/browser/sync_file_system/local/syncable_file_system_operation.h"
12 #include "chrome/browser/sync_file_system/sync_file_system_service.h"
13 #include "chrome/browser/sync_file_system/sync_file_system_service_factory.h"
14 #include "chrome/browser/sync_file_system/syncable_file_system_util.h"
15 #include "content/public/browser/browser_thread.h"
16 #include "content/public/browser/notification_service.h"
17 #include "webkit/browser/blob/file_stream_reader.h"
18 #include "webkit/browser/fileapi/file_stream_writer.h"
19 #include "webkit/browser/fileapi/file_system_context.h"
20 #include "webkit/browser/fileapi/file_system_operation.h"
21 #include "webkit/common/fileapi/file_system_util.h"
23 using content::BrowserThread
;
25 namespace sync_file_system
{
29 bool CalledOnUIThread() {
30 // Ensure that these methods are called on the UI thread, except for unittests
31 // where a UI thread might not have been created.
32 return BrowserThread::CurrentlyOn(BrowserThread::UI
) ||
33 !BrowserThread::IsMessageLoopValid(BrowserThread::UI
);
38 SyncFileSystemBackend::ProfileHolder::ProfileHolder(Profile
* profile
)
40 DCHECK(CalledOnUIThread());
42 chrome::NOTIFICATION_PROFILE_DESTROYED
,
43 content::Source
<Profile
>(profile_
));
46 void SyncFileSystemBackend::ProfileHolder::Observe(
48 const content::NotificationSource
& source
,
49 const content::NotificationDetails
& details
) {
50 DCHECK(CalledOnUIThread());
51 DCHECK_EQ(chrome::NOTIFICATION_PROFILE_DESTROYED
, type
);
52 DCHECK_EQ(profile_
, content::Source
<Profile
>(source
).ptr());
54 registrar_
.RemoveAll();
57 Profile
* SyncFileSystemBackend::ProfileHolder::GetProfile() {
58 DCHECK(CalledOnUIThread());
62 SyncFileSystemBackend::SyncFileSystemBackend(Profile
* profile
)
64 skip_initialize_syncfs_service_for_testing_(false) {
65 DCHECK(CalledOnUIThread());
67 profile_holder_
.reset(new ProfileHolder(profile
));
69 // Register the service name here to enable to crack an URL on SyncFileSystem
70 // even if SyncFileSystemService has not started yet.
71 RegisterSyncableFileSystem();
74 SyncFileSystemBackend::~SyncFileSystemBackend() {
75 if (change_tracker_
) {
76 GetDelegate()->file_task_runner()->DeleteSoon(
77 FROM_HERE
, change_tracker_
.release());
80 if (profile_holder_
&& !CalledOnUIThread()) {
81 BrowserThread::DeleteSoon(
82 BrowserThread::UI
, FROM_HERE
, profile_holder_
.release());
87 SyncFileSystemBackend
* SyncFileSystemBackend::CreateForTesting() {
88 DCHECK(CalledOnUIThread());
89 SyncFileSystemBackend
* backend
= new SyncFileSystemBackend(NULL
);
90 backend
->skip_initialize_syncfs_service_for_testing_
= true;
94 bool SyncFileSystemBackend::CanHandleType(
95 fileapi::FileSystemType type
) const {
96 return type
== fileapi::kFileSystemTypeSyncable
||
97 type
== fileapi::kFileSystemTypeSyncableForInternalSync
;
100 void SyncFileSystemBackend::Initialize(fileapi::FileSystemContext
* context
) {
105 fileapi::SandboxFileSystemBackendDelegate
* delegate
= GetDelegate();
106 delegate
->RegisterQuotaUpdateObserver(fileapi::kFileSystemTypeSyncable
);
107 delegate
->RegisterQuotaUpdateObserver(
108 fileapi::kFileSystemTypeSyncableForInternalSync
);
111 void SyncFileSystemBackend::ResolveURL(const fileapi::FileSystemURL
& url
,
112 fileapi::OpenFileSystemMode mode
,
113 const OpenFileSystemCallback
& callback
) {
114 DCHECK(CanHandleType(url
.type()));
116 if (skip_initialize_syncfs_service_for_testing_
) {
117 GetDelegate()->OpenFileSystem(url
.origin(),
121 GetSyncableFileSystemRootURI(url
.origin()));
125 // It is safe to pass Unretained(this) since |context_| owns it.
126 SyncStatusCallback initialize_callback
=
127 base::Bind(&SyncFileSystemBackend::DidInitializeSyncFileSystemService
,
128 base::Unretained(this),
129 make_scoped_refptr(context_
),
134 InitializeSyncFileSystemService(url
.origin(), initialize_callback
);
137 fileapi::AsyncFileUtil
* SyncFileSystemBackend::GetAsyncFileUtil(
138 fileapi::FileSystemType type
) {
139 return GetDelegate()->file_util();
142 fileapi::CopyOrMoveFileValidatorFactory
*
143 SyncFileSystemBackend::GetCopyOrMoveFileValidatorFactory(
144 fileapi::FileSystemType type
,
145 base::File::Error
* error_code
) {
147 *error_code
= base::File::FILE_OK
;
151 fileapi::FileSystemOperation
*
152 SyncFileSystemBackend::CreateFileSystemOperation(
153 const fileapi::FileSystemURL
& url
,
154 fileapi::FileSystemContext
* context
,
155 base::File::Error
* error_code
) const {
156 DCHECK(CanHandleType(url
.type()));
160 scoped_ptr
<fileapi::FileSystemOperationContext
> operation_context
=
161 GetDelegate()->CreateFileSystemOperationContext(url
, context
, error_code
);
162 if (!operation_context
)
165 if (url
.type() == fileapi::kFileSystemTypeSyncableForInternalSync
) {
166 return fileapi::FileSystemOperation::Create(
167 url
, context
, operation_context
.Pass());
170 return new SyncableFileSystemOperation(
171 url
, context
, operation_context
.Pass());
174 bool SyncFileSystemBackend::SupportsStreaming(
175 const fileapi::FileSystemURL
& url
) const {
179 scoped_ptr
<webkit_blob::FileStreamReader
>
180 SyncFileSystemBackend::CreateFileStreamReader(
181 const fileapi::FileSystemURL
& url
,
183 const base::Time
& expected_modification_time
,
184 fileapi::FileSystemContext
* context
) const {
185 DCHECK(CanHandleType(url
.type()));
186 return GetDelegate()->CreateFileStreamReader(
187 url
, offset
, expected_modification_time
, context
);
190 scoped_ptr
<fileapi::FileStreamWriter
>
191 SyncFileSystemBackend::CreateFileStreamWriter(
192 const fileapi::FileSystemURL
& url
,
194 fileapi::FileSystemContext
* context
) const {
195 DCHECK(CanHandleType(url
.type()));
196 return GetDelegate()->CreateFileStreamWriter(
197 url
, offset
, context
, fileapi::kFileSystemTypeSyncableForInternalSync
);
200 fileapi::FileSystemQuotaUtil
* SyncFileSystemBackend::GetQuotaUtil() {
201 return GetDelegate();
205 SyncFileSystemBackend
* SyncFileSystemBackend::GetBackend(
206 const fileapi::FileSystemContext
* file_system_context
) {
207 DCHECK(file_system_context
);
208 return static_cast<SyncFileSystemBackend
*>(
209 file_system_context
->GetFileSystemBackend(
210 fileapi::kFileSystemTypeSyncable
));
213 void SyncFileSystemBackend::SetLocalFileChangeTracker(
214 scoped_ptr
<LocalFileChangeTracker
> tracker
) {
215 DCHECK(!change_tracker_
);
217 change_tracker_
= tracker
.Pass();
219 fileapi::SandboxFileSystemBackendDelegate
* delegate
= GetDelegate();
220 delegate
->AddFileUpdateObserver(
221 fileapi::kFileSystemTypeSyncable
,
222 change_tracker_
.get(),
223 delegate
->file_task_runner());
224 delegate
->AddFileChangeObserver(
225 fileapi::kFileSystemTypeSyncable
,
226 change_tracker_
.get(),
227 delegate
->file_task_runner());
230 void SyncFileSystemBackend::set_sync_context(
231 LocalFileSyncContext
* sync_context
) {
232 DCHECK(!sync_context_
);
233 sync_context_
= sync_context
;
236 fileapi::SandboxFileSystemBackendDelegate
*
237 SyncFileSystemBackend::GetDelegate() const {
239 DCHECK(context_
->sandbox_delegate());
240 return context_
->sandbox_delegate();
243 void SyncFileSystemBackend::InitializeSyncFileSystemService(
244 const GURL
& origin_url
,
245 const SyncStatusCallback
& callback
) {
246 // Repost to switch from IO thread to UI thread.
247 if (!BrowserThread::CurrentlyOn(BrowserThread::UI
)) {
248 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
249 // It is safe to pass Unretained(this) (see comments in OpenFileSystem()).
250 BrowserThread::PostTask(
251 BrowserThread::UI
, FROM_HERE
,
252 base::Bind(&SyncFileSystemBackend::InitializeSyncFileSystemService
,
253 base::Unretained(this), origin_url
, callback
));
257 if (!profile_holder_
->GetProfile()) {
258 // Profile was destroyed.
259 callback
.Run(SYNC_FILE_ERROR_FAILED
);
263 SyncFileSystemService
* service
= SyncFileSystemServiceFactory::GetForProfile(
264 profile_holder_
->GetProfile());
266 service
->InitializeForApp(context_
, origin_url
, callback
);
269 void SyncFileSystemBackend::DidInitializeSyncFileSystemService(
270 fileapi::FileSystemContext
* context
,
271 const GURL
& origin_url
,
272 fileapi::FileSystemType type
,
273 fileapi::OpenFileSystemMode mode
,
274 const OpenFileSystemCallback
& callback
,
275 SyncStatusCode status
) {
276 // Repost to switch from UI thread to IO thread.
277 if (!BrowserThread::CurrentlyOn(BrowserThread::IO
)) {
278 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
279 // It is safe to pass Unretained(this) since |context| owns it.
280 BrowserThread::PostTask(
281 BrowserThread::IO
, FROM_HERE
,
282 base::Bind(&SyncFileSystemBackend::DidInitializeSyncFileSystemService
,
283 base::Unretained(this), make_scoped_refptr(context
),
284 origin_url
, type
, mode
, callback
, status
));
288 if (status
!= sync_file_system::SYNC_STATUS_OK
) {
289 callback
.Run(GURL(), std::string(),
290 SyncStatusCodeToFileError(status
));
294 callback
.Run(GetSyncableFileSystemRootURI(origin_url
),
295 GetFileSystemName(origin_url
, type
),
296 base::File::FILE_OK
);
299 } // namespace sync_file_system