Home | History | Annotate | Download | only in local
      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 <string>
      8 
      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"
     24 
     25 using content::BrowserThread;
     26 
     27 namespace sync_file_system {
     28 
     29 namespace {
     30 
     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);
     36 }
     37 
     38 }  // namespace
     39 
     40 SyncFileSystemBackend::ProfileHolder::ProfileHolder(Profile* profile)
     41     : profile_(profile) {
     42   DCHECK(CalledOnUIThread());
     43   registrar_.Add(this,
     44                  chrome::NOTIFICATION_PROFILE_DESTROYED,
     45                  content::Source<Profile>(profile_));
     46 }
     47 
     48 void SyncFileSystemBackend::ProfileHolder::Observe(
     49     int type,
     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());
     55   profile_ = NULL;
     56   registrar_.RemoveAll();
     57 }
     58 
     59 Profile* SyncFileSystemBackend::ProfileHolder::GetProfile() {
     60   DCHECK(CalledOnUIThread());
     61   return profile_;
     62 }
     63 
     64 SyncFileSystemBackend::SyncFileSystemBackend(Profile* profile)
     65     : context_(NULL),
     66       skip_initialize_syncfs_service_for_testing_(false) {
     67   DCHECK(CalledOnUIThread());
     68   if (profile)
     69     profile_holder_.reset(new ProfileHolder(profile));
     70 
     71   // Register the service name here to enable to crack an URL on SyncFileSystem
     72   // even if SyncFileSystemService has not started yet.
     73   RegisterSyncableFileSystem();
     74 }
     75 
     76 SyncFileSystemBackend::~SyncFileSystemBackend() {
     77   if (change_tracker_) {
     78     GetDelegate()->file_task_runner()->DeleteSoon(
     79         FROM_HERE, change_tracker_.release());
     80   }
     81 
     82   if (profile_holder_ && !CalledOnUIThread()) {
     83     BrowserThread::DeleteSoon(
     84         BrowserThread::UI, FROM_HERE, profile_holder_.release());
     85   }
     86 }
     87 
     88 // static
     89 SyncFileSystemBackend* SyncFileSystemBackend::CreateForTesting() {
     90   DCHECK(CalledOnUIThread());
     91   SyncFileSystemBackend* backend = new SyncFileSystemBackend(NULL);
     92   backend->skip_initialize_syncfs_service_for_testing_ = true;
     93   return backend;
     94 }
     95 
     96 bool SyncFileSystemBackend::CanHandleType(storage::FileSystemType type) const {
     97   return type == storage::kFileSystemTypeSyncable ||
     98          type == storage::kFileSystemTypeSyncableForInternalSync;
     99 }
    100 
    101 void SyncFileSystemBackend::Initialize(storage::FileSystemContext* context) {
    102   DCHECK(context);
    103   DCHECK(!context_);
    104   context_ = context;
    105 
    106   storage::SandboxFileSystemBackendDelegate* delegate = GetDelegate();
    107   delegate->RegisterQuotaUpdateObserver(storage::kFileSystemTypeSyncable);
    108   delegate->RegisterQuotaUpdateObserver(
    109       storage::kFileSystemTypeSyncableForInternalSync);
    110 }
    111 
    112 void SyncFileSystemBackend::ResolveURL(const storage::FileSystemURL& url,
    113                                        storage::OpenFileSystemMode mode,
    114                                        const OpenFileSystemCallback& callback) {
    115   DCHECK(CanHandleType(url.type()));
    116 
    117   if (skip_initialize_syncfs_service_for_testing_) {
    118     GetDelegate()->OpenFileSystem(url.origin(),
    119                                   url.type(),
    120                                   mode,
    121                                   callback,
    122                                   GetSyncableFileSystemRootURI(url.origin()));
    123     return;
    124   }
    125 
    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_),
    131                  url.origin(),
    132                  url.type(),
    133                  mode,
    134                  callback);
    135   InitializeSyncFileSystemService(url.origin(), initialize_callback);
    136 }
    137 
    138 storage::AsyncFileUtil* SyncFileSystemBackend::GetAsyncFileUtil(
    139     storage::FileSystemType type) {
    140   return GetDelegate()->file_util();
    141 }
    142 
    143 storage::WatcherManager* SyncFileSystemBackend::GetWatcherManager(
    144     storage::FileSystemType type) {
    145   return NULL;
    146 }
    147 
    148 storage::CopyOrMoveFileValidatorFactory*
    149 SyncFileSystemBackend::GetCopyOrMoveFileValidatorFactory(
    150     storage::FileSystemType type,
    151     base::File::Error* error_code) {
    152   DCHECK(error_code);
    153   *error_code = base::File::FILE_OK;
    154   return NULL;
    155 }
    156 
    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()));
    162   DCHECK(context);
    163   DCHECK(error_code);
    164 
    165   scoped_ptr<storage::FileSystemOperationContext> operation_context =
    166       GetDelegate()->CreateFileSystemOperationContext(url, context, error_code);
    167   if (!operation_context)
    168     return NULL;
    169 
    170   if (url.type() == storage::kFileSystemTypeSyncableForInternalSync) {
    171     return storage::FileSystemOperation::Create(
    172         url, context, operation_context.Pass());
    173   }
    174 
    175   return new SyncableFileSystemOperation(
    176       url, context, operation_context.Pass());
    177 }
    178 
    179 bool SyncFileSystemBackend::SupportsStreaming(
    180     const storage::FileSystemURL& url) const {
    181   return false;
    182 }
    183 
    184 bool SyncFileSystemBackend::HasInplaceCopyImplementation(
    185     storage::FileSystemType type) const {
    186   return false;
    187 }
    188 
    189 scoped_ptr<storage::FileStreamReader>
    190 SyncFileSystemBackend::CreateFileStreamReader(
    191     const storage::FileSystemURL& url,
    192     int64 offset,
    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);
    199 }
    200 
    201 scoped_ptr<storage::FileStreamWriter>
    202 SyncFileSystemBackend::CreateFileStreamWriter(
    203     const storage::FileSystemURL& url,
    204     int64 offset,
    205     storage::FileSystemContext* context) const {
    206   DCHECK(CanHandleType(url.type()));
    207   return GetDelegate()->CreateFileStreamWriter(
    208       url, offset, context, storage::kFileSystemTypeSyncableForInternalSync);
    209 }
    210 
    211 storage::FileSystemQuotaUtil* SyncFileSystemBackend::GetQuotaUtil() {
    212   return GetDelegate();
    213 }
    214 
    215 const storage::UpdateObserverList* SyncFileSystemBackend::GetUpdateObservers(
    216     storage::FileSystemType type) const {
    217   return GetDelegate()->GetUpdateObservers(type);
    218 }
    219 
    220 const storage::ChangeObserverList* SyncFileSystemBackend::GetChangeObservers(
    221     storage::FileSystemType type) const {
    222   return GetDelegate()->GetChangeObservers(type);
    223 }
    224 
    225 const storage::AccessObserverList* SyncFileSystemBackend::GetAccessObservers(
    226     storage::FileSystemType type) const {
    227   return GetDelegate()->GetAccessObservers(type);
    228 }
    229 
    230 // static
    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));
    237 }
    238 
    239 void SyncFileSystemBackend::SetLocalFileChangeTracker(
    240     scoped_ptr<LocalFileChangeTracker> tracker) {
    241   DCHECK(!change_tracker_);
    242   DCHECK(tracker);
    243   change_tracker_ = tracker.Pass();
    244 
    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());
    252 }
    253 
    254 void SyncFileSystemBackend::set_sync_context(
    255     LocalFileSyncContext* sync_context) {
    256   DCHECK(!sync_context_.get());
    257   sync_context_ = sync_context;
    258 }
    259 
    260 storage::SandboxFileSystemBackendDelegate* SyncFileSystemBackend::GetDelegate()
    261     const {
    262   DCHECK(context_);
    263   DCHECK(context_->sandbox_delegate());
    264   return context_->sandbox_delegate();
    265 }
    266 
    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));
    278     return;
    279   }
    280 
    281   if (!profile_holder_->GetProfile()) {
    282     // Profile was destroyed.
    283     callback.Run(SYNC_FILE_ERROR_FAILED);
    284     return;
    285   }
    286 
    287   SyncFileSystemService* service = SyncFileSystemServiceFactory::GetForProfile(
    288           profile_holder_->GetProfile());
    289   DCHECK(service);
    290   service->InitializeForApp(context_, origin_url, callback);
    291 }
    292 
    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));
    309     return;
    310   }
    311 
    312   if (status != sync_file_system::SYNC_STATUS_OK) {
    313     callback.Run(GURL(), std::string(),
    314                  SyncStatusCodeToFileError(status));
    315     return;
    316   }
    317 
    318   callback.Run(GetSyncableFileSystemRootURI(origin_url),
    319                GetFileSystemName(origin_url, type),
    320                base::File::FILE_OK);
    321 }
    322 
    323 }  // namespace sync_file_system
    324