Home | History | Annotate | Download | only in fileapi
      1 // Copyright (c) 2012 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 "webkit/browser/fileapi/file_system_context.h"
      6 
      7 #include "base/bind.h"
      8 #include "base/single_thread_task_runner.h"
      9 #include "base/stl_util.h"
     10 #include "base/task_runner_util.h"
     11 #include "url/gurl.h"
     12 #include "webkit/browser/blob/file_stream_reader.h"
     13 #include "webkit/browser/fileapi/copy_or_move_file_validator.h"
     14 #include "webkit/browser/fileapi/external_mount_points.h"
     15 #include "webkit/browser/fileapi/file_permission_policy.h"
     16 #include "webkit/browser/fileapi/file_stream_writer.h"
     17 #include "webkit/browser/fileapi/file_system_file_util.h"
     18 #include "webkit/browser/fileapi/file_system_operation.h"
     19 #include "webkit/browser/fileapi/file_system_operation_runner.h"
     20 #include "webkit/browser/fileapi/file_system_options.h"
     21 #include "webkit/browser/fileapi/file_system_quota_client.h"
     22 #include "webkit/browser/fileapi/file_system_url.h"
     23 #include "webkit/browser/fileapi/isolated_context.h"
     24 #include "webkit/browser/fileapi/isolated_file_system_backend.h"
     25 #include "webkit/browser/fileapi/mount_points.h"
     26 #include "webkit/browser/fileapi/sandbox_file_system_backend.h"
     27 #include "webkit/browser/fileapi/test_file_system_backend.h"
     28 #include "webkit/browser/quota/quota_manager.h"
     29 #include "webkit/browser/quota/special_storage_policy.h"
     30 #include "webkit/common/fileapi/file_system_util.h"
     31 
     32 using quota::QuotaClient;
     33 
     34 namespace fileapi {
     35 
     36 namespace {
     37 
     38 QuotaClient* CreateQuotaClient(
     39     FileSystemContext* context,
     40     bool is_incognito) {
     41   return new FileSystemQuotaClient(context, is_incognito);
     42 }
     43 
     44 void DidOpenFileSystem(
     45     const FileSystemContext::OpenFileSystemCallback& callback,
     46     const GURL& filesystem_root,
     47     const std::string& filesystem_name,
     48     base::PlatformFileError error) {
     49   callback.Run(error, filesystem_name, filesystem_root);
     50 }
     51 
     52 }  // namespace
     53 
     54 // static
     55 int FileSystemContext::GetPermissionPolicy(FileSystemType type) {
     56   switch (type) {
     57     case kFileSystemTypeTemporary:
     58     case kFileSystemTypePersistent:
     59     case kFileSystemTypeSyncable:
     60       return FILE_PERMISSION_SANDBOX;
     61 
     62     case kFileSystemTypeDrive:
     63     case kFileSystemTypeNativeForPlatformApp:
     64     case kFileSystemTypeNativeLocal:
     65       return FILE_PERMISSION_USE_FILE_PERMISSION;
     66 
     67     case kFileSystemTypeRestrictedNativeLocal:
     68       return FILE_PERMISSION_READ_ONLY |
     69              FILE_PERMISSION_USE_FILE_PERMISSION;
     70 
     71     // Following types are only accessed via IsolatedFileSystem, and
     72     // don't have their own permission policies.
     73     case kFileSystemTypeDeviceMedia:
     74     case kFileSystemTypeDragged:
     75     case kFileSystemTypeForTransientFile:
     76     case kFileSystemTypeItunes:
     77     case kFileSystemTypeNativeMedia:
     78     case kFileSystemTypePicasa:
     79       return FILE_PERMISSION_ALWAYS_DENY;
     80 
     81     // Following types only appear as mount_type, and will not be
     82     // queried for their permission policies.
     83     case kFileSystemTypeIsolated:
     84     case kFileSystemTypeExternal:
     85       return FILE_PERMISSION_ALWAYS_DENY;
     86 
     87     // Following types should not be used to access files by FileAPI clients.
     88     case kFileSystemTypeTest:
     89     case kFileSystemTypeSyncableForInternalSync:
     90     case kFileSystemInternalTypeEnumEnd:
     91     case kFileSystemInternalTypeEnumStart:
     92     case kFileSystemTypeUnknown:
     93       return FILE_PERMISSION_ALWAYS_DENY;
     94   }
     95   NOTREACHED();
     96   return FILE_PERMISSION_ALWAYS_DENY;
     97 }
     98 
     99 FileSystemContext::FileSystemContext(
    100     base::SingleThreadTaskRunner* io_task_runner,
    101     base::SequencedTaskRunner* file_task_runner,
    102     ExternalMountPoints* external_mount_points,
    103     quota::SpecialStoragePolicy* special_storage_policy,
    104     quota::QuotaManagerProxy* quota_manager_proxy,
    105     ScopedVector<FileSystemBackend> additional_backends,
    106     const base::FilePath& partition_path,
    107     const FileSystemOptions& options)
    108     : io_task_runner_(io_task_runner),
    109       default_file_task_runner_(file_task_runner),
    110       quota_manager_proxy_(quota_manager_proxy),
    111       sandbox_context_(new SandboxContext(
    112           quota_manager_proxy,
    113           file_task_runner,
    114           partition_path,
    115           special_storage_policy,
    116           options)),
    117       sandbox_backend_(new SandboxFileSystemBackend(
    118           sandbox_context_.get())),
    119       isolated_backend_(new IsolatedFileSystemBackend()),
    120       additional_backends_(additional_backends.Pass()),
    121       external_mount_points_(external_mount_points),
    122       partition_path_(partition_path),
    123       operation_runner_(new FileSystemOperationRunner(this)) {
    124   if (quota_manager_proxy) {
    125     quota_manager_proxy->RegisterClient(CreateQuotaClient(
    126             this, options.is_incognito()));
    127   }
    128 
    129   RegisterBackend(sandbox_backend_.get());
    130   RegisterBackend(isolated_backend_.get());
    131 
    132   for (ScopedVector<FileSystemBackend>::const_iterator iter =
    133           additional_backends_.begin();
    134        iter != additional_backends_.end(); ++iter) {
    135     RegisterBackend(*iter);
    136   }
    137 
    138   sandbox_backend_->Initialize(this);
    139   isolated_backend_->Initialize(this);
    140   for (ScopedVector<FileSystemBackend>::const_iterator iter =
    141           additional_backends_.begin();
    142        iter != additional_backends_.end(); ++iter) {
    143     (*iter)->Initialize(this);
    144   }
    145 
    146   // Additional mount points must be added before regular system-wide
    147   // mount points.
    148   if (external_mount_points)
    149     url_crackers_.push_back(external_mount_points);
    150   url_crackers_.push_back(ExternalMountPoints::GetSystemInstance());
    151   url_crackers_.push_back(IsolatedContext::GetInstance());
    152 }
    153 
    154 bool FileSystemContext::DeleteDataForOriginOnFileThread(
    155     const GURL& origin_url) {
    156   DCHECK(default_file_task_runner()->RunsTasksOnCurrentThread());
    157   DCHECK(origin_url == origin_url.GetOrigin());
    158 
    159   bool success = true;
    160   for (FileSystemBackendMap::iterator iter = backend_map_.begin();
    161        iter != backend_map_.end();
    162        ++iter) {
    163     FileSystemBackend* backend = iter->second;
    164     if (!backend->GetQuotaUtil())
    165       continue;
    166     if (backend->GetQuotaUtil()->DeleteOriginDataOnFileThread(
    167             this, quota_manager_proxy(), origin_url, iter->first)
    168             != base::PLATFORM_FILE_OK) {
    169       // Continue the loop, but record the failure.
    170       success = false;
    171     }
    172   }
    173 
    174   return success;
    175 }
    176 
    177 void FileSystemContext::Shutdown() {
    178   if (!io_task_runner_->RunsTasksOnCurrentThread()) {
    179     io_task_runner_->PostTask(
    180         FROM_HERE, base::Bind(&FileSystemContext::Shutdown,
    181                               make_scoped_refptr(this)));
    182     return;
    183   }
    184   operation_runner_->Shutdown();
    185 }
    186 
    187 FileSystemQuotaUtil*
    188 FileSystemContext::GetQuotaUtil(FileSystemType type) const {
    189   FileSystemBackend* backend = GetFileSystemBackend(type);
    190   if (!backend)
    191     return NULL;
    192   return backend->GetQuotaUtil();
    193 }
    194 
    195 AsyncFileUtil* FileSystemContext::GetAsyncFileUtil(
    196     FileSystemType type) const {
    197   FileSystemBackend* backend = GetFileSystemBackend(type);
    198   if (!backend)
    199     return NULL;
    200   return backend->GetAsyncFileUtil(type);
    201 }
    202 
    203 FileSystemFileUtil* FileSystemContext::GetFileUtil(
    204     FileSystemType type) const {
    205   FileSystemBackend* backend = GetFileSystemBackend(type);
    206   if (!backend)
    207     return NULL;
    208   return backend->GetFileUtil(type);
    209 }
    210 
    211 CopyOrMoveFileValidatorFactory*
    212 FileSystemContext::GetCopyOrMoveFileValidatorFactory(
    213     FileSystemType type, base::PlatformFileError* error_code) const {
    214   DCHECK(error_code);
    215   *error_code = base::PLATFORM_FILE_OK;
    216   FileSystemBackend* backend = GetFileSystemBackend(type);
    217   if (!backend)
    218     return NULL;
    219   return backend->GetCopyOrMoveFileValidatorFactory(
    220       type, error_code);
    221 }
    222 
    223 FileSystemBackend* FileSystemContext::GetFileSystemBackend(
    224     FileSystemType type) const {
    225   FileSystemBackendMap::const_iterator found = backend_map_.find(type);
    226   if (found != backend_map_.end())
    227     return found->second;
    228   NOTREACHED() << "Unknown filesystem type: " << type;
    229   return NULL;
    230 }
    231 
    232 bool FileSystemContext::IsSandboxFileSystem(FileSystemType type) const {
    233   return GetQuotaUtil(type) != NULL;
    234 }
    235 
    236 const UpdateObserverList* FileSystemContext::GetUpdateObservers(
    237     FileSystemType type) const {
    238   FileSystemBackend* backend = GetFileSystemBackend(type);
    239   if (backend->GetQuotaUtil())
    240     return backend->GetQuotaUtil()->GetUpdateObservers(type);
    241   return NULL;
    242 }
    243 
    244 const AccessObserverList* FileSystemContext::GetAccessObservers(
    245     FileSystemType type) const {
    246   FileSystemBackend* backend = GetFileSystemBackend(type);
    247   if (backend->GetQuotaUtil())
    248     return backend->GetQuotaUtil()->GetAccessObservers(type);
    249   return NULL;
    250 }
    251 
    252 void FileSystemContext::GetFileSystemTypes(
    253     std::vector<FileSystemType>* types) const {
    254   types->clear();
    255   for (FileSystemBackendMap::const_iterator iter = backend_map_.begin();
    256        iter != backend_map_.end(); ++iter)
    257     types->push_back(iter->first);
    258 }
    259 
    260 ExternalFileSystemBackend*
    261 FileSystemContext::external_backend() const {
    262   return static_cast<ExternalFileSystemBackend*>(
    263       GetFileSystemBackend(kFileSystemTypeExternal));
    264 }
    265 
    266 void FileSystemContext::OpenFileSystem(
    267     const GURL& origin_url,
    268     FileSystemType type,
    269     OpenFileSystemMode mode,
    270     const OpenFileSystemCallback& callback) {
    271   DCHECK(!callback.is_null());
    272 
    273   FileSystemBackend* backend = GetFileSystemBackend(type);
    274   if (!backend) {
    275     callback.Run(base::PLATFORM_FILE_ERROR_SECURITY, std::string(), GURL());
    276     return;
    277   }
    278 
    279   backend->OpenFileSystem(origin_url, type, mode,
    280                           base::Bind(&DidOpenFileSystem, callback));
    281 }
    282 
    283 void FileSystemContext::DeleteFileSystem(
    284     const GURL& origin_url,
    285     FileSystemType type,
    286     const DeleteFileSystemCallback& callback) {
    287   DCHECK(origin_url == origin_url.GetOrigin());
    288   FileSystemBackend* backend = GetFileSystemBackend(type);
    289   if (!backend) {
    290     callback.Run(base::PLATFORM_FILE_ERROR_SECURITY);
    291     return;
    292   }
    293   if (!backend->GetQuotaUtil()) {
    294     callback.Run(base::PLATFORM_FILE_ERROR_INVALID_OPERATION);
    295     return;
    296   }
    297 
    298   base::PostTaskAndReplyWithResult(
    299       default_file_task_runner(),
    300       FROM_HERE,
    301       // It is safe to pass Unretained(quota_util) since context owns it.
    302       base::Bind(&FileSystemQuotaUtil::DeleteOriginDataOnFileThread,
    303                  base::Unretained(backend->GetQuotaUtil()),
    304                  make_scoped_refptr(this),
    305                  base::Unretained(quota_manager_proxy()),
    306                  origin_url,
    307                  type),
    308       callback);
    309 }
    310 
    311 scoped_ptr<webkit_blob::FileStreamReader>
    312 FileSystemContext::CreateFileStreamReader(
    313     const FileSystemURL& url,
    314     int64 offset,
    315     const base::Time& expected_modification_time) {
    316   if (!url.is_valid())
    317     return scoped_ptr<webkit_blob::FileStreamReader>();
    318   FileSystemBackend* backend = GetFileSystemBackend(url.type());
    319   if (!backend)
    320     return scoped_ptr<webkit_blob::FileStreamReader>();
    321   return backend->CreateFileStreamReader(
    322       url, offset, expected_modification_time, this);
    323 }
    324 
    325 scoped_ptr<FileStreamWriter> FileSystemContext::CreateFileStreamWriter(
    326     const FileSystemURL& url,
    327     int64 offset) {
    328   if (!url.is_valid())
    329     return scoped_ptr<FileStreamWriter>();
    330   FileSystemBackend* backend = GetFileSystemBackend(url.type());
    331   if (!backend)
    332     return scoped_ptr<FileStreamWriter>();
    333   return backend->CreateFileStreamWriter(url, offset, this);
    334 }
    335 
    336 scoped_ptr<FileSystemOperationRunner>
    337 FileSystemContext::CreateFileSystemOperationRunner() {
    338   return make_scoped_ptr(new FileSystemOperationRunner(this));
    339 }
    340 
    341 FileSystemURL FileSystemContext::CrackURL(const GURL& url) const {
    342   return CrackFileSystemURL(FileSystemURL(url));
    343 }
    344 
    345 FileSystemURL FileSystemContext::CreateCrackedFileSystemURL(
    346     const GURL& origin,
    347     FileSystemType type,
    348     const base::FilePath& path) const {
    349   return CrackFileSystemURL(FileSystemURL(origin, type, path));
    350 }
    351 
    352 #if defined(OS_CHROMEOS) && defined(GOOGLE_CHROME_BUILD)
    353 void FileSystemContext::EnableTemporaryFileSystemInIncognito() {
    354   sandbox_backend_->set_enable_temporary_file_system_in_incognito(true);
    355 }
    356 #endif
    357 
    358 FileSystemContext::~FileSystemContext() {
    359 }
    360 
    361 void FileSystemContext::DeleteOnCorrectThread() const {
    362   if (!io_task_runner_->RunsTasksOnCurrentThread() &&
    363       io_task_runner_->DeleteSoon(FROM_HERE, this)) {
    364     return;
    365   }
    366   delete this;
    367 }
    368 
    369 FileSystemOperation* FileSystemContext::CreateFileSystemOperation(
    370     const FileSystemURL& url, base::PlatformFileError* error_code) {
    371   if (!url.is_valid()) {
    372     if (error_code)
    373       *error_code = base::PLATFORM_FILE_ERROR_INVALID_URL;
    374     return NULL;
    375   }
    376 
    377   FileSystemBackend* backend = GetFileSystemBackend(url.type());
    378   if (!backend) {
    379     if (error_code)
    380       *error_code = base::PLATFORM_FILE_ERROR_FAILED;
    381     return NULL;
    382   }
    383 
    384   base::PlatformFileError fs_error = base::PLATFORM_FILE_OK;
    385   FileSystemOperation* operation =
    386       backend->CreateFileSystemOperation(url, this, &fs_error);
    387 
    388   if (error_code)
    389     *error_code = fs_error;
    390   return operation;
    391 }
    392 
    393 FileSystemURL FileSystemContext::CrackFileSystemURL(
    394     const FileSystemURL& url) const {
    395   if (!url.is_valid())
    396     return FileSystemURL();
    397 
    398   // The returned value in case there is no crackers which can crack the url.
    399   // This is valid situation for non isolated/external file systems.
    400   FileSystemURL current = url;
    401 
    402   // File system may be mounted multiple times (e.g., an isolated filesystem on
    403   // top of an external filesystem). Hence cracking needs to be iterated.
    404   for (;;) {
    405     FileSystemURL cracked = current;
    406     for (size_t i = 0; i < url_crackers_.size(); ++i) {
    407       if (!url_crackers_[i]->HandlesFileSystemMountType(current.type()))
    408         continue;
    409       cracked = url_crackers_[i]->CrackFileSystemURL(current);
    410       if (cracked.is_valid())
    411         break;
    412     }
    413     if (cracked == current)
    414       break;
    415     current = cracked;
    416   }
    417   return current;
    418 }
    419 
    420 void FileSystemContext::RegisterBackend(
    421     FileSystemBackend* backend) {
    422   const FileSystemType mount_types[] = {
    423     kFileSystemTypeTemporary,
    424     kFileSystemTypePersistent,
    425     kFileSystemTypeIsolated,
    426     kFileSystemTypeExternal,
    427   };
    428   // Register file system backends for public mount types.
    429   for (size_t j = 0; j < ARRAYSIZE_UNSAFE(mount_types); ++j) {
    430     if (backend->CanHandleType(mount_types[j])) {
    431       const bool inserted = backend_map_.insert(
    432           std::make_pair(mount_types[j], backend)).second;
    433       DCHECK(inserted);
    434     }
    435   }
    436   // Register file system backends for internal types.
    437   for (int t = kFileSystemInternalTypeEnumStart + 1;
    438        t < kFileSystemInternalTypeEnumEnd; ++t) {
    439     FileSystemType type = static_cast<FileSystemType>(t);
    440     if (backend->CanHandleType(type)) {
    441       const bool inserted = backend_map_.insert(
    442           std::make_pair(type, backend)).second;
    443       DCHECK(inserted);
    444     }
    445   }
    446 }
    447 
    448 }  // namespace fileapi
    449