• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.
4 
5 #include "chrome/browser/sync_file_system/local/sync_file_system_backend.h"
6 
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"
22 
23 using content::BrowserThread;
24 
25 namespace sync_file_system {
26 
27 namespace {
28 
CalledOnUIThread()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);
34 }
35 
36 }  // namespace
37 
ProfileHolder(Profile * profile)38 SyncFileSystemBackend::ProfileHolder::ProfileHolder(Profile* profile)
39     : profile_(profile) {
40   DCHECK(CalledOnUIThread());
41   registrar_.Add(this,
42                  chrome::NOTIFICATION_PROFILE_DESTROYED,
43                  content::Source<Profile>(profile_));
44 }
45 
Observe(int type,const content::NotificationSource & source,const content::NotificationDetails & details)46 void SyncFileSystemBackend::ProfileHolder::Observe(
47     int type,
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());
53   profile_ = NULL;
54   registrar_.RemoveAll();
55 }
56 
GetProfile()57 Profile* SyncFileSystemBackend::ProfileHolder::GetProfile() {
58   DCHECK(CalledOnUIThread());
59   return profile_;
60 }
61 
SyncFileSystemBackend(Profile * profile)62 SyncFileSystemBackend::SyncFileSystemBackend(Profile* profile)
63     : context_(NULL),
64       skip_initialize_syncfs_service_for_testing_(false) {
65   DCHECK(CalledOnUIThread());
66   if (profile)
67     profile_holder_.reset(new ProfileHolder(profile));
68 
69   // Register the service name here to enable to crack an URL on SyncFileSystem
70   // even if SyncFileSystemService has not started yet.
71   RegisterSyncableFileSystem();
72 }
73 
~SyncFileSystemBackend()74 SyncFileSystemBackend::~SyncFileSystemBackend() {
75   if (change_tracker_) {
76     GetDelegate()->file_task_runner()->DeleteSoon(
77         FROM_HERE, change_tracker_.release());
78   }
79 
80   if (profile_holder_ && !CalledOnUIThread()) {
81     BrowserThread::DeleteSoon(
82         BrowserThread::UI, FROM_HERE, profile_holder_.release());
83   }
84 }
85 
86 // static
CreateForTesting()87 SyncFileSystemBackend* SyncFileSystemBackend::CreateForTesting() {
88   DCHECK(CalledOnUIThread());
89   SyncFileSystemBackend* backend = new SyncFileSystemBackend(NULL);
90   backend->skip_initialize_syncfs_service_for_testing_ = true;
91   return backend;
92 }
93 
CanHandleType(fileapi::FileSystemType type) const94 bool SyncFileSystemBackend::CanHandleType(
95     fileapi::FileSystemType type) const {
96   return type == fileapi::kFileSystemTypeSyncable ||
97          type == fileapi::kFileSystemTypeSyncableForInternalSync;
98 }
99 
Initialize(fileapi::FileSystemContext * context)100 void SyncFileSystemBackend::Initialize(fileapi::FileSystemContext* context) {
101   DCHECK(context);
102   DCHECK(!context_);
103   context_ = context;
104 
105   fileapi::SandboxFileSystemBackendDelegate* delegate = GetDelegate();
106   delegate->RegisterQuotaUpdateObserver(fileapi::kFileSystemTypeSyncable);
107   delegate->RegisterQuotaUpdateObserver(
108       fileapi::kFileSystemTypeSyncableForInternalSync);
109 }
110 
ResolveURL(const fileapi::FileSystemURL & url,fileapi::OpenFileSystemMode mode,const OpenFileSystemCallback & callback)111 void SyncFileSystemBackend::ResolveURL(const fileapi::FileSystemURL& url,
112                                        fileapi::OpenFileSystemMode mode,
113                                        const OpenFileSystemCallback& callback) {
114   DCHECK(CanHandleType(url.type()));
115 
116   if (skip_initialize_syncfs_service_for_testing_) {
117     GetDelegate()->OpenFileSystem(url.origin(),
118                                   url.type(),
119                                   mode,
120                                   callback,
121                                   GetSyncableFileSystemRootURI(url.origin()));
122     return;
123   }
124 
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_),
130                  url.origin(),
131                  url.type(),
132                  mode,
133                  callback);
134   InitializeSyncFileSystemService(url.origin(), initialize_callback);
135 }
136 
GetAsyncFileUtil(fileapi::FileSystemType type)137 fileapi::AsyncFileUtil* SyncFileSystemBackend::GetAsyncFileUtil(
138     fileapi::FileSystemType type) {
139   return GetDelegate()->file_util();
140 }
141 
142 fileapi::CopyOrMoveFileValidatorFactory*
GetCopyOrMoveFileValidatorFactory(fileapi::FileSystemType type,base::File::Error * error_code)143 SyncFileSystemBackend::GetCopyOrMoveFileValidatorFactory(
144     fileapi::FileSystemType type,
145     base::File::Error* error_code) {
146   DCHECK(error_code);
147   *error_code = base::File::FILE_OK;
148   return NULL;
149 }
150 
151 fileapi::FileSystemOperation*
CreateFileSystemOperation(const fileapi::FileSystemURL & url,fileapi::FileSystemContext * context,base::File::Error * error_code) const152 SyncFileSystemBackend::CreateFileSystemOperation(
153     const fileapi::FileSystemURL& url,
154     fileapi::FileSystemContext* context,
155     base::File::Error* error_code) const {
156   DCHECK(CanHandleType(url.type()));
157   DCHECK(context);
158   DCHECK(error_code);
159 
160   scoped_ptr<fileapi::FileSystemOperationContext> operation_context =
161       GetDelegate()->CreateFileSystemOperationContext(url, context, error_code);
162   if (!operation_context)
163     return NULL;
164 
165   if (url.type() == fileapi::kFileSystemTypeSyncableForInternalSync) {
166     return fileapi::FileSystemOperation::Create(
167         url, context, operation_context.Pass());
168   }
169 
170   return new SyncableFileSystemOperation(
171       url, context, operation_context.Pass());
172 }
173 
SupportsStreaming(const fileapi::FileSystemURL & url) const174 bool SyncFileSystemBackend::SupportsStreaming(
175     const fileapi::FileSystemURL& url) const {
176   return false;
177 }
178 
179 scoped_ptr<webkit_blob::FileStreamReader>
CreateFileStreamReader(const fileapi::FileSystemURL & url,int64 offset,const base::Time & expected_modification_time,fileapi::FileSystemContext * context) const180 SyncFileSystemBackend::CreateFileStreamReader(
181     const fileapi::FileSystemURL& url,
182     int64 offset,
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);
188 }
189 
190 scoped_ptr<fileapi::FileStreamWriter>
CreateFileStreamWriter(const fileapi::FileSystemURL & url,int64 offset,fileapi::FileSystemContext * context) const191 SyncFileSystemBackend::CreateFileStreamWriter(
192     const fileapi::FileSystemURL& url,
193     int64 offset,
194     fileapi::FileSystemContext* context) const {
195   DCHECK(CanHandleType(url.type()));
196   return GetDelegate()->CreateFileStreamWriter(
197       url, offset, context, fileapi::kFileSystemTypeSyncableForInternalSync);
198 }
199 
GetQuotaUtil()200 fileapi::FileSystemQuotaUtil* SyncFileSystemBackend::GetQuotaUtil() {
201   return GetDelegate();
202 }
203 
204 // static
GetBackend(const fileapi::FileSystemContext * file_system_context)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));
211 }
212 
SetLocalFileChangeTracker(scoped_ptr<LocalFileChangeTracker> tracker)213 void SyncFileSystemBackend::SetLocalFileChangeTracker(
214     scoped_ptr<LocalFileChangeTracker> tracker) {
215   DCHECK(!change_tracker_);
216   DCHECK(tracker);
217   change_tracker_ = tracker.Pass();
218 
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());
228 }
229 
set_sync_context(LocalFileSyncContext * sync_context)230 void SyncFileSystemBackend::set_sync_context(
231     LocalFileSyncContext* sync_context) {
232   DCHECK(!sync_context_);
233   sync_context_ = sync_context;
234 }
235 
236 fileapi::SandboxFileSystemBackendDelegate*
GetDelegate() const237 SyncFileSystemBackend::GetDelegate() const {
238   DCHECK(context_);
239   DCHECK(context_->sandbox_delegate());
240   return context_->sandbox_delegate();
241 }
242 
InitializeSyncFileSystemService(const GURL & origin_url,const SyncStatusCallback & callback)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));
254     return;
255   }
256 
257   if (!profile_holder_->GetProfile()) {
258     // Profile was destroyed.
259     callback.Run(SYNC_FILE_ERROR_FAILED);
260     return;
261   }
262 
263   SyncFileSystemService* service = SyncFileSystemServiceFactory::GetForProfile(
264           profile_holder_->GetProfile());
265   DCHECK(service);
266   service->InitializeForApp(context_, origin_url, callback);
267 }
268 
DidInitializeSyncFileSystemService(fileapi::FileSystemContext * context,const GURL & origin_url,fileapi::FileSystemType type,fileapi::OpenFileSystemMode mode,const OpenFileSystemCallback & callback,SyncStatusCode status)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));
285     return;
286   }
287 
288   if (status != sync_file_system::SYNC_STATUS_OK) {
289     callback.Run(GURL(), std::string(),
290                  SyncStatusCodeToFileError(status));
291     return;
292   }
293 
294   callback.Run(GetSyncableFileSystemRootURI(origin_url),
295                GetFileSystemName(origin_url, type),
296                base::File::FILE_OK);
297 }
298 
299 }  // namespace sync_file_system
300