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 "webkit/browser/blob/file_stream_reader.h"
20 #include "webkit/browser/fileapi/file_stream_writer.h"
21 #include "webkit/browser/fileapi/file_system_context.h"
22 #include "webkit/browser/fileapi/file_system_operation.h"
23 #include "webkit/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(NULL
);
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 const base::Time
& expected_modification_time
,
194 storage::FileSystemContext
* context
) const {
195 DCHECK(CanHandleType(url
.type()));
196 return GetDelegate()->CreateFileStreamReader(
197 url
, offset
, expected_modification_time
, context
);
200 scoped_ptr
<storage::FileStreamWriter
>
201 SyncFileSystemBackend::CreateFileStreamWriter(
202 const storage::FileSystemURL
& url
,
204 storage::FileSystemContext
* context
) const {
205 DCHECK(CanHandleType(url
.type()));
206 return GetDelegate()->CreateFileStreamWriter(
207 url
, offset
, context
, storage::kFileSystemTypeSyncableForInternalSync
);
210 storage::FileSystemQuotaUtil
* SyncFileSystemBackend::GetQuotaUtil() {
211 return GetDelegate();
215 SyncFileSystemBackend
* SyncFileSystemBackend::GetBackend(
216 const storage::FileSystemContext
* file_system_context
) {
217 DCHECK(file_system_context
);
218 return static_cast<SyncFileSystemBackend
*>(
219 file_system_context
->GetFileSystemBackend(
220 storage::kFileSystemTypeSyncable
));
223 void SyncFileSystemBackend::SetLocalFileChangeTracker(
224 scoped_ptr
<LocalFileChangeTracker
> tracker
) {
225 DCHECK(!change_tracker_
);
227 change_tracker_
= tracker
.Pass();
229 storage::SandboxFileSystemBackendDelegate
* delegate
= GetDelegate();
230 delegate
->AddFileUpdateObserver(storage::kFileSystemTypeSyncable
,
231 change_tracker_
.get(),
232 delegate
->file_task_runner());
233 delegate
->AddFileChangeObserver(storage::kFileSystemTypeSyncable
,
234 change_tracker_
.get(),
235 delegate
->file_task_runner());
238 void SyncFileSystemBackend::set_sync_context(
239 LocalFileSyncContext
* sync_context
) {
240 DCHECK(!sync_context_
.get());
241 sync_context_
= sync_context
;
244 storage::SandboxFileSystemBackendDelegate
* SyncFileSystemBackend::GetDelegate()
247 DCHECK(context_
->sandbox_delegate());
248 return context_
->sandbox_delegate();
251 void SyncFileSystemBackend::InitializeSyncFileSystemService(
252 const GURL
& origin_url
,
253 const SyncStatusCallback
& callback
) {
254 // Repost to switch from IO thread to UI thread.
255 if (!BrowserThread::CurrentlyOn(BrowserThread::UI
)) {
256 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
257 // It is safe to pass Unretained(this) (see comments in OpenFileSystem()).
258 BrowserThread::PostTask(
259 BrowserThread::UI
, FROM_HERE
,
260 base::Bind(&SyncFileSystemBackend::InitializeSyncFileSystemService
,
261 base::Unretained(this), origin_url
, callback
));
265 if (!profile_holder_
->GetProfile()) {
266 // Profile was destroyed.
267 callback
.Run(SYNC_FILE_ERROR_FAILED
);
271 SyncFileSystemService
* service
= SyncFileSystemServiceFactory::GetForProfile(
272 profile_holder_
->GetProfile());
274 service
->InitializeForApp(context_
, origin_url
, callback
);
277 void SyncFileSystemBackend::DidInitializeSyncFileSystemService(
278 storage::FileSystemContext
* context
,
279 const GURL
& origin_url
,
280 storage::FileSystemType type
,
281 storage::OpenFileSystemMode mode
,
282 const OpenFileSystemCallback
& callback
,
283 SyncStatusCode status
) {
284 // Repost to switch from UI thread to IO thread.
285 if (!BrowserThread::CurrentlyOn(BrowserThread::IO
)) {
286 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
287 // It is safe to pass Unretained(this) since |context| owns it.
288 BrowserThread::PostTask(
289 BrowserThread::IO
, FROM_HERE
,
290 base::Bind(&SyncFileSystemBackend::DidInitializeSyncFileSystemService
,
291 base::Unretained(this), make_scoped_refptr(context
),
292 origin_url
, type
, mode
, callback
, status
));
296 if (status
!= sync_file_system::SYNC_STATUS_OK
) {
297 callback
.Run(GURL(), std::string(),
298 SyncStatusCodeToFileError(status
));
302 callback
.Run(GetSyncableFileSystemRootURI(origin_url
),
303 GetFileSystemName(origin_url
, type
),
304 base::File::FILE_OK
);
307 } // namespace sync_file_system