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::OpenFileSystem(
112 const GURL
& origin_url
,
113 fileapi::FileSystemType type
,
114 fileapi::OpenFileSystemMode mode
,
115 const OpenFileSystemCallback
& callback
) {
116 DCHECK(CanHandleType(type
));
118 if (skip_initialize_syncfs_service_for_testing_
) {
119 GetDelegate()->OpenFileSystem(origin_url
, type
, mode
, callback
,
120 GetSyncableFileSystemRootURI(origin_url
));
124 // It is safe to pass Unretained(this) since |context_| owns it.
125 SyncStatusCallback initialize_callback
=
126 base::Bind(&SyncFileSystemBackend::DidInitializeSyncFileSystemService
,
127 base::Unretained(this), make_scoped_refptr(context_
),
128 origin_url
, type
, mode
, callback
);
129 InitializeSyncFileSystemService(origin_url
, initialize_callback
);
132 fileapi::AsyncFileUtil
* SyncFileSystemBackend::GetAsyncFileUtil(
133 fileapi::FileSystemType type
) {
134 return GetDelegate()->file_util();
137 fileapi::CopyOrMoveFileValidatorFactory
*
138 SyncFileSystemBackend::GetCopyOrMoveFileValidatorFactory(
139 fileapi::FileSystemType type
,
140 base::PlatformFileError
* error_code
) {
142 *error_code
= base::PLATFORM_FILE_OK
;
146 fileapi::FileSystemOperation
*
147 SyncFileSystemBackend::CreateFileSystemOperation(
148 const fileapi::FileSystemURL
& url
,
149 fileapi::FileSystemContext
* context
,
150 base::PlatformFileError
* error_code
) const {
151 DCHECK(CanHandleType(url
.type()));
155 scoped_ptr
<fileapi::FileSystemOperationContext
> operation_context
=
156 GetDelegate()->CreateFileSystemOperationContext(url
, context
, error_code
);
157 if (!operation_context
)
160 if (url
.type() == fileapi::kFileSystemTypeSyncableForInternalSync
) {
161 return fileapi::FileSystemOperation::Create(
162 url
, context
, operation_context
.Pass());
165 return new SyncableFileSystemOperation(
166 url
, context
, operation_context
.Pass());
169 scoped_ptr
<webkit_blob::FileStreamReader
>
170 SyncFileSystemBackend::CreateFileStreamReader(
171 const fileapi::FileSystemURL
& url
,
173 const base::Time
& expected_modification_time
,
174 fileapi::FileSystemContext
* context
) const {
175 DCHECK(CanHandleType(url
.type()));
176 return GetDelegate()->CreateFileStreamReader(
177 url
, offset
, expected_modification_time
, context
);
180 scoped_ptr
<fileapi::FileStreamWriter
>
181 SyncFileSystemBackend::CreateFileStreamWriter(
182 const fileapi::FileSystemURL
& url
,
184 fileapi::FileSystemContext
* context
) const {
185 DCHECK(CanHandleType(url
.type()));
186 return GetDelegate()->CreateFileStreamWriter(
187 url
, offset
, context
, fileapi::kFileSystemTypeSyncableForInternalSync
);
190 fileapi::FileSystemQuotaUtil
* SyncFileSystemBackend::GetQuotaUtil() {
191 return GetDelegate();
195 SyncFileSystemBackend
* SyncFileSystemBackend::GetBackend(
196 const fileapi::FileSystemContext
* file_system_context
) {
197 DCHECK(file_system_context
);
198 return static_cast<SyncFileSystemBackend
*>(
199 file_system_context
->GetFileSystemBackend(
200 fileapi::kFileSystemTypeSyncable
));
203 void SyncFileSystemBackend::SetLocalFileChangeTracker(
204 scoped_ptr
<LocalFileChangeTracker
> tracker
) {
205 DCHECK(!change_tracker_
);
207 change_tracker_
= tracker
.Pass();
209 fileapi::SandboxFileSystemBackendDelegate
* delegate
= GetDelegate();
210 delegate
->AddFileUpdateObserver(
211 fileapi::kFileSystemTypeSyncable
,
212 change_tracker_
.get(),
213 delegate
->file_task_runner());
214 delegate
->AddFileChangeObserver(
215 fileapi::kFileSystemTypeSyncable
,
216 change_tracker_
.get(),
217 delegate
->file_task_runner());
220 void SyncFileSystemBackend::set_sync_context(
221 LocalFileSyncContext
* sync_context
) {
222 DCHECK(!sync_context_
);
223 sync_context_
= sync_context
;
226 fileapi::SandboxFileSystemBackendDelegate
*
227 SyncFileSystemBackend::GetDelegate() const {
229 DCHECK(context_
->sandbox_delegate());
230 return context_
->sandbox_delegate();
233 void SyncFileSystemBackend::InitializeSyncFileSystemService(
234 const GURL
& origin_url
,
235 const SyncStatusCallback
& callback
) {
236 // Repost to switch from IO thread to UI thread.
237 if (!BrowserThread::CurrentlyOn(BrowserThread::UI
)) {
238 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
239 // It is safe to pass Unretained(this) (see comments in OpenFileSystem()).
240 BrowserThread::PostTask(
241 BrowserThread::UI
, FROM_HERE
,
242 base::Bind(&SyncFileSystemBackend::InitializeSyncFileSystemService
,
243 base::Unretained(this), origin_url
, callback
));
247 if (!profile_holder_
->GetProfile()) {
248 // Profile was destroyed.
249 callback
.Run(SYNC_FILE_ERROR_FAILED
);
253 SyncFileSystemService
* service
= SyncFileSystemServiceFactory::GetForProfile(
254 profile_holder_
->GetProfile());
256 service
->InitializeForApp(context_
, origin_url
, callback
);
259 void SyncFileSystemBackend::DidInitializeSyncFileSystemService(
260 fileapi::FileSystemContext
* context
,
261 const GURL
& origin_url
,
262 fileapi::FileSystemType type
,
263 fileapi::OpenFileSystemMode mode
,
264 const OpenFileSystemCallback
& callback
,
265 SyncStatusCode status
) {
266 // Repost to switch from UI thread to IO thread.
267 if (!BrowserThread::CurrentlyOn(BrowserThread::IO
)) {
268 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
269 // It is safe to pass Unretained(this) since |context| owns it.
270 BrowserThread::PostTask(
271 BrowserThread::IO
, FROM_HERE
,
272 base::Bind(&SyncFileSystemBackend::DidInitializeSyncFileSystemService
,
273 base::Unretained(this), make_scoped_refptr(context
),
274 origin_url
, type
, mode
, callback
, status
));
278 if (status
!= sync_file_system::SYNC_STATUS_OK
) {
279 callback
.Run(GURL(), std::string(),
280 SyncStatusCodeToPlatformFileError(status
));
284 callback
.Run(GetSyncableFileSystemRootURI(origin_url
),
285 GetFileSystemName(origin_url
, type
),
286 base::PLATFORM_FILE_OK
);
289 } // namespace sync_file_system