Home | History | Annotate | Download | only in fileapi
      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/chromeos/fileapi/file_system_backend.h"
      6 
      7 #include "base/logging.h"
      8 #include "base/memory/scoped_ptr.h"
      9 #include "base/message_loop/message_loop.h"
     10 #include "base/path_service.h"
     11 #include "base/strings/stringprintf.h"
     12 #include "base/strings/utf_string_conversions.h"
     13 #include "base/synchronization/lock.h"
     14 #include "chrome/browser/chromeos/fileapi/file_access_permissions.h"
     15 #include "chrome/browser/chromeos/fileapi/file_system_backend_delegate.h"
     16 #include "chromeos/dbus/cros_disks_client.h"
     17 #include "webkit/browser/blob/file_stream_reader.h"
     18 #include "webkit/browser/fileapi/async_file_util_adapter.h"
     19 #include "webkit/browser/fileapi/external_mount_points.h"
     20 #include "webkit/browser/fileapi/file_system_context.h"
     21 #include "webkit/browser/fileapi/file_system_file_stream_reader.h"
     22 #include "webkit/browser/fileapi/file_system_operation_context.h"
     23 #include "webkit/browser/fileapi/file_system_operation_impl.h"
     24 #include "webkit/browser/fileapi/file_system_url.h"
     25 #include "webkit/browser/fileapi/isolated_context.h"
     26 #include "webkit/browser/fileapi/isolated_file_util.h"
     27 #include "webkit/browser/fileapi/local_file_stream_writer.h"
     28 
     29 namespace {
     30 
     31 const char kChromeUIScheme[] = "chrome";
     32 
     33 }  // namespace
     34 
     35 namespace chromeos {
     36 
     37 // static
     38 bool FileSystemBackend::CanHandleURL(const fileapi::FileSystemURL& url) {
     39   if (!url.is_valid())
     40     return false;
     41   return url.type() == fileapi::kFileSystemTypeNativeLocal ||
     42          url.type() == fileapi::kFileSystemTypeRestrictedNativeLocal ||
     43          url.type() == fileapi::kFileSystemTypeDrive;
     44 }
     45 
     46 FileSystemBackend::FileSystemBackend(
     47     FileSystemBackendDelegate* drive_delegate,
     48     scoped_refptr<quota::SpecialStoragePolicy> special_storage_policy,
     49     scoped_refptr<fileapi::ExternalMountPoints> mount_points,
     50     fileapi::ExternalMountPoints* system_mount_points)
     51     : special_storage_policy_(special_storage_policy),
     52       file_access_permissions_(new FileAccessPermissions()),
     53       local_file_util_(new fileapi::AsyncFileUtilAdapter(
     54           new fileapi::IsolatedFileUtil())),
     55       drive_delegate_(drive_delegate),
     56       mount_points_(mount_points),
     57       system_mount_points_(system_mount_points) {
     58 }
     59 
     60 FileSystemBackend::~FileSystemBackend() {
     61 }
     62 
     63 void FileSystemBackend::AddSystemMountPoints() {
     64   // RegisterFileSystem() is no-op if the mount point with the same name
     65   // already exists, hence it's safe to call without checking if a mount
     66   // point already exists or not.
     67 
     68   // TODO(satorux): "Downloads" directory should probably be per-profile. For
     69   // this to be per-profile, a unique directory path should be chosen per
     70   // profile, and the mount point should be added to
     71   // mount_points_. crbug.com/247236
     72   base::FilePath home_path;
     73   if (PathService::Get(base::DIR_HOME, &home_path)) {
     74     system_mount_points_->RegisterFileSystem(
     75         "Downloads",
     76         fileapi::kFileSystemTypeNativeLocal,
     77         home_path.AppendASCII("Downloads"));
     78   }
     79 
     80   system_mount_points_->RegisterFileSystem(
     81       "archive",
     82       fileapi::kFileSystemTypeNativeLocal,
     83       chromeos::CrosDisksClient::GetArchiveMountPoint());
     84   system_mount_points_->RegisterFileSystem(
     85       "removable",
     86       fileapi::kFileSystemTypeNativeLocal,
     87       chromeos::CrosDisksClient::GetRemovableDiskMountPoint());
     88   system_mount_points_->RegisterFileSystem(
     89       "oem",
     90       fileapi::kFileSystemTypeRestrictedNativeLocal,
     91       base::FilePath(FILE_PATH_LITERAL("/usr/share/oem")));
     92 }
     93 
     94 bool FileSystemBackend::CanHandleType(fileapi::FileSystemType type) const {
     95   switch (type) {
     96     case fileapi::kFileSystemTypeExternal:
     97     case fileapi::kFileSystemTypeDrive:
     98     case fileapi::kFileSystemTypeRestrictedNativeLocal:
     99     case fileapi::kFileSystemTypeNativeLocal:
    100     case fileapi::kFileSystemTypeNativeForPlatformApp:
    101       return true;
    102     default:
    103       return false;
    104   }
    105 }
    106 
    107 void FileSystemBackend::Initialize(fileapi::FileSystemContext* context) {
    108 }
    109 
    110 void FileSystemBackend::OpenFileSystem(
    111     const GURL& origin_url,
    112     fileapi::FileSystemType type,
    113     fileapi::OpenFileSystemMode mode,
    114     const OpenFileSystemCallback& callback) {
    115   DCHECK(fileapi::IsolatedContext::IsIsolatedType(type));
    116   // Nothing to validate for external filesystem.
    117   callback.Run(GetFileSystemRootURI(origin_url, type),
    118                GetFileSystemName(origin_url, type),
    119                base::PLATFORM_FILE_OK);
    120 }
    121 
    122 fileapi::FileSystemQuotaUtil* FileSystemBackend::GetQuotaUtil() {
    123   // No quota support.
    124   return NULL;
    125 }
    126 
    127 bool FileSystemBackend::IsAccessAllowed(
    128     const fileapi::FileSystemURL& url) const {
    129   if (!url.is_valid())
    130     return false;
    131 
    132   // Permit access to mount points from internal WebUI.
    133   const GURL& origin_url = url.origin();
    134   if (origin_url.SchemeIs(kChromeUIScheme))
    135     return true;
    136 
    137   // No extra check is needed for isolated file systems.
    138   if (url.mount_type() == fileapi::kFileSystemTypeIsolated)
    139     return true;
    140 
    141   if (!CanHandleURL(url))
    142     return false;
    143 
    144   std::string extension_id = origin_url.host();
    145   // TODO(mtomasz): Temporarily whitelist TimeScapes. Remove this in M-31.
    146   // See: crbug.com/271946
    147   if (extension_id == "mlbmkoenclnokonejhlfakkeabdlmpek" &&
    148       url.type() == fileapi::kFileSystemTypeRestrictedNativeLocal) {
    149     return true;
    150   }
    151 
    152   // Check first to make sure this extension has fileBrowserHander permissions.
    153   if (!special_storage_policy_->IsFileHandler(extension_id))
    154     return false;
    155 
    156   return file_access_permissions_->HasAccessPermission(extension_id,
    157                                                        url.virtual_path());
    158 }
    159 
    160 void FileSystemBackend::GrantFullAccessToExtension(
    161     const std::string& extension_id) {
    162   DCHECK(special_storage_policy_->IsFileHandler(extension_id));
    163   if (!special_storage_policy_->IsFileHandler(extension_id))
    164     return;
    165 
    166   std::vector<fileapi::MountPoints::MountPointInfo> files;
    167   mount_points_->AddMountPointInfosTo(&files);
    168   system_mount_points_->AddMountPointInfosTo(&files);
    169 
    170   for (size_t i = 0; i < files.size(); ++i) {
    171     file_access_permissions_->GrantAccessPermission(
    172         extension_id,
    173         base::FilePath::FromUTF8Unsafe(files[i].name));
    174   }
    175 }
    176 
    177 void FileSystemBackend::GrantFileAccessToExtension(
    178     const std::string& extension_id, const base::FilePath& virtual_path) {
    179   // All we care about here is access from extensions for now.
    180   DCHECK(special_storage_policy_->IsFileHandler(extension_id));
    181   if (!special_storage_policy_->IsFileHandler(extension_id))
    182     return;
    183 
    184   std::string id;
    185   fileapi::FileSystemType type;
    186   base::FilePath path;
    187   if (!mount_points_->CrackVirtualPath(virtual_path, &id, &type, &path) &&
    188       !system_mount_points_->CrackVirtualPath(virtual_path,
    189                                               &id, &type, &path)) {
    190     return;
    191   }
    192 
    193   if (type == fileapi::kFileSystemTypeRestrictedNativeLocal) {
    194     LOG(ERROR) << "Can't grant access for restricted mount point";
    195     return;
    196   }
    197 
    198   file_access_permissions_->GrantAccessPermission(extension_id, virtual_path);
    199 }
    200 
    201 void FileSystemBackend::RevokeAccessForExtension(
    202       const std::string& extension_id) {
    203   file_access_permissions_->RevokePermissions(extension_id);
    204 }
    205 
    206 std::vector<base::FilePath> FileSystemBackend::GetRootDirectories() const {
    207   std::vector<fileapi::MountPoints::MountPointInfo> mount_points;
    208   mount_points_->AddMountPointInfosTo(&mount_points);
    209   system_mount_points_->AddMountPointInfosTo(&mount_points);
    210 
    211   std::vector<base::FilePath> root_dirs;
    212   for (size_t i = 0; i < mount_points.size(); ++i)
    213     root_dirs.push_back(mount_points[i].path);
    214   return root_dirs;
    215 }
    216 
    217 fileapi::FileSystemFileUtil* FileSystemBackend::GetFileUtil(
    218     fileapi::FileSystemType type) {
    219   DCHECK(type == fileapi::kFileSystemTypeNativeLocal ||
    220          type == fileapi::kFileSystemTypeRestrictedNativeLocal);
    221   return local_file_util_->sync_file_util();
    222 }
    223 
    224 fileapi::AsyncFileUtil* FileSystemBackend::GetAsyncFileUtil(
    225     fileapi::FileSystemType type) {
    226   if (type == fileapi::kFileSystemTypeDrive)
    227     return drive_delegate_->GetAsyncFileUtil(type);
    228 
    229   DCHECK(type == fileapi::kFileSystemTypeNativeLocal ||
    230          type == fileapi::kFileSystemTypeRestrictedNativeLocal);
    231   return local_file_util_.get();
    232 }
    233 
    234 fileapi::CopyOrMoveFileValidatorFactory*
    235 FileSystemBackend::GetCopyOrMoveFileValidatorFactory(
    236     fileapi::FileSystemType type, base::PlatformFileError* error_code) {
    237   DCHECK(error_code);
    238   *error_code = base::PLATFORM_FILE_OK;
    239   return NULL;
    240 }
    241 
    242 fileapi::FileSystemOperation* FileSystemBackend::CreateFileSystemOperation(
    243     const fileapi::FileSystemURL& url,
    244     fileapi::FileSystemContext* context,
    245     base::PlatformFileError* error_code) const {
    246   DCHECK(url.is_valid());
    247 
    248   if (!IsAccessAllowed(url)) {
    249     *error_code = base::PLATFORM_FILE_ERROR_SECURITY;
    250     return NULL;
    251   }
    252 
    253   DCHECK(url.type() == fileapi::kFileSystemTypeNativeLocal ||
    254          url.type() == fileapi::kFileSystemTypeRestrictedNativeLocal ||
    255          url.type() == fileapi::kFileSystemTypeDrive);
    256   scoped_ptr<fileapi::FileSystemOperationContext> operation_context(
    257       new fileapi::FileSystemOperationContext(context));
    258   operation_context->set_root_path(GetFileSystemRootPath(url));
    259   return new fileapi::FileSystemOperationImpl(url, context,
    260                                               operation_context.Pass());
    261 }
    262 
    263 scoped_ptr<webkit_blob::FileStreamReader>
    264 FileSystemBackend::CreateFileStreamReader(
    265     const fileapi::FileSystemURL& url,
    266     int64 offset,
    267     const base::Time& expected_modification_time,
    268     fileapi::FileSystemContext* context) const {
    269   DCHECK(url.is_valid());
    270 
    271   if (!IsAccessAllowed(url))
    272     return scoped_ptr<webkit_blob::FileStreamReader>();
    273 
    274   if (url.type() == fileapi::kFileSystemTypeDrive) {
    275     return drive_delegate_->CreateFileStreamReader(
    276         url, offset, expected_modification_time, context);
    277   }
    278 
    279   return scoped_ptr<webkit_blob::FileStreamReader>(
    280       new fileapi::FileSystemFileStreamReader(
    281           context, url, offset, expected_modification_time));
    282 }
    283 
    284 scoped_ptr<fileapi::FileStreamWriter>
    285 FileSystemBackend::CreateFileStreamWriter(
    286     const fileapi::FileSystemURL& url,
    287     int64 offset,
    288     fileapi::FileSystemContext* context) const {
    289   DCHECK(url.is_valid());
    290 
    291   if (!IsAccessAllowed(url))
    292     return scoped_ptr<fileapi::FileStreamWriter>();
    293 
    294   if (url.type() == fileapi::kFileSystemTypeDrive)
    295     return drive_delegate_->CreateFileStreamWriter(url, offset, context);
    296 
    297   if (url.type() == fileapi::kFileSystemTypeRestrictedNativeLocal)
    298     return scoped_ptr<fileapi::FileStreamWriter>();
    299 
    300   DCHECK(url.type() == fileapi::kFileSystemTypeNativeLocal);
    301   return scoped_ptr<fileapi::FileStreamWriter>(
    302       new fileapi::LocalFileStreamWriter(
    303           context->default_file_task_runner(), url.path(), offset));
    304 }
    305 
    306 bool FileSystemBackend::GetVirtualPath(
    307     const base::FilePath& filesystem_path,
    308     base::FilePath* virtual_path) {
    309   return mount_points_->GetVirtualPath(filesystem_path, virtual_path) ||
    310          system_mount_points_->GetVirtualPath(filesystem_path, virtual_path);
    311 }
    312 
    313 base::FilePath FileSystemBackend::GetFileSystemRootPath(
    314     const fileapi::FileSystemURL& url) const {
    315   DCHECK(fileapi::IsolatedContext::IsIsolatedType(url.mount_type()));
    316   if (!url.is_valid())
    317     return base::FilePath();
    318 
    319   base::FilePath root_path;
    320   std::string mount_name = url.filesystem_id();
    321   if (!mount_points_->GetRegisteredPath(mount_name, &root_path) &&
    322       !system_mount_points_->GetRegisteredPath(mount_name, &root_path)) {
    323     return base::FilePath();
    324   }
    325 
    326   return root_path.DirName();
    327 }
    328 
    329 }  // namespace chromeos
    330