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/strings/stringprintf.h"
     10 #include "chrome/browser/chromeos/fileapi/file_access_permissions.h"
     11 #include "chrome/browser/chromeos/fileapi/file_system_backend_delegate.h"
     12 #include "chrome/browser/media_galleries/fileapi/media_file_system_backend.h"
     13 #include "chromeos/dbus/cros_disks_client.h"
     14 #include "webkit/browser/blob/file_stream_reader.h"
     15 #include "webkit/browser/fileapi/async_file_util.h"
     16 #include "webkit/browser/fileapi/external_mount_points.h"
     17 #include "webkit/browser/fileapi/file_stream_writer.h"
     18 #include "webkit/browser/fileapi/file_system_context.h"
     19 #include "webkit/browser/fileapi/file_system_operation.h"
     20 #include "webkit/browser/fileapi/file_system_operation_context.h"
     21 #include "webkit/browser/fileapi/file_system_url.h"
     22 
     23 namespace chromeos {
     24 
     25 // static
     26 bool FileSystemBackend::CanHandleURL(const fileapi::FileSystemURL& url) {
     27   if (!url.is_valid())
     28     return false;
     29   return url.type() == fileapi::kFileSystemTypeNativeLocal ||
     30          url.type() == fileapi::kFileSystemTypeRestrictedNativeLocal ||
     31          url.type() == fileapi::kFileSystemTypeDrive ||
     32          url.type() == fileapi::kFileSystemTypeProvided ||
     33          url.type() == fileapi::kFileSystemTypeDeviceMediaAsFileStorage;
     34 }
     35 
     36 FileSystemBackend::FileSystemBackend(
     37     FileSystemBackendDelegate* drive_delegate,
     38     FileSystemBackendDelegate* file_system_provider_delegate,
     39     FileSystemBackendDelegate* mtp_delegate,
     40     scoped_refptr<quota::SpecialStoragePolicy> special_storage_policy,
     41     scoped_refptr<fileapi::ExternalMountPoints> mount_points,
     42     fileapi::ExternalMountPoints* system_mount_points)
     43     : special_storage_policy_(special_storage_policy),
     44       file_access_permissions_(new FileAccessPermissions()),
     45       local_file_util_(fileapi::AsyncFileUtil::CreateForLocalFileSystem()),
     46       drive_delegate_(drive_delegate),
     47       file_system_provider_delegate_(file_system_provider_delegate),
     48       mtp_delegate_(mtp_delegate),
     49       mount_points_(mount_points),
     50       system_mount_points_(system_mount_points) {}
     51 
     52 FileSystemBackend::~FileSystemBackend() {
     53 }
     54 
     55 void FileSystemBackend::AddSystemMountPoints() {
     56   // RegisterFileSystem() is no-op if the mount point with the same name
     57   // already exists, hence it's safe to call without checking if a mount
     58   // point already exists or not.
     59   system_mount_points_->RegisterFileSystem(
     60       "archive",
     61       fileapi::kFileSystemTypeNativeLocal,
     62       fileapi::FileSystemMountOption(),
     63       chromeos::CrosDisksClient::GetArchiveMountPoint());
     64   system_mount_points_->RegisterFileSystem(
     65       "removable",
     66       fileapi::kFileSystemTypeNativeLocal,
     67       fileapi::FileSystemMountOption(fileapi::COPY_SYNC_OPTION_SYNC),
     68       chromeos::CrosDisksClient::GetRemovableDiskMountPoint());
     69   system_mount_points_->RegisterFileSystem(
     70       "oem",
     71       fileapi::kFileSystemTypeRestrictedNativeLocal,
     72       fileapi::FileSystemMountOption(),
     73       base::FilePath(FILE_PATH_LITERAL("/usr/share/oem")));
     74 }
     75 
     76 bool FileSystemBackend::CanHandleType(fileapi::FileSystemType type) const {
     77   switch (type) {
     78     case fileapi::kFileSystemTypeExternal:
     79     case fileapi::kFileSystemTypeDrive:
     80     case fileapi::kFileSystemTypeRestrictedNativeLocal:
     81     case fileapi::kFileSystemTypeNativeLocal:
     82     case fileapi::kFileSystemTypeNativeForPlatformApp:
     83     case fileapi::kFileSystemTypeDeviceMediaAsFileStorage:
     84     case fileapi::kFileSystemTypeProvided:
     85       return true;
     86     default:
     87       return false;
     88   }
     89 }
     90 
     91 void FileSystemBackend::Initialize(fileapi::FileSystemContext* context) {
     92 }
     93 
     94 void FileSystemBackend::ResolveURL(const fileapi::FileSystemURL& url,
     95                                    fileapi::OpenFileSystemMode mode,
     96                                    const OpenFileSystemCallback& callback) {
     97   std::string id;
     98   fileapi::FileSystemType type;
     99   std::string cracked_id;
    100   base::FilePath path;
    101   fileapi::FileSystemMountOption option;
    102   if (!mount_points_->CrackVirtualPath(
    103            url.virtual_path(), &id, &type, &cracked_id, &path, &option) &&
    104       !system_mount_points_->CrackVirtualPath(
    105            url.virtual_path(), &id, &type, &cracked_id, &path, &option)) {
    106     // Not under a mount point, so return an error, since the root is not
    107     // accessible.
    108     GURL root_url = GURL(fileapi::GetExternalFileSystemRootURIString(
    109         url.origin(), std::string()));
    110     callback.Run(root_url, std::string(), base::File::FILE_ERROR_SECURITY);
    111     return;
    112   }
    113 
    114   std::string name;
    115   // Construct a URL restricted to the found mount point.
    116   std::string root_url =
    117       fileapi::GetExternalFileSystemRootURIString(url.origin(), id);
    118 
    119   // For removable and archives, the file system root is the external mount
    120   // point plus the inner mount point.
    121   if (id == "archive" || id == "removable") {
    122     std::vector<std::string> components;
    123     url.virtual_path().GetComponents(&components);
    124     DCHECK_EQ(id, components.at(0));
    125     if (components.size() < 2) {
    126       // Unable to access /archive and /removable directories directly. The
    127       // inner mount name must be specified.
    128       callback.Run(
    129           GURL(root_url), std::string(), base::File::FILE_ERROR_SECURITY);
    130       return;
    131     }
    132     std::string inner_mount_name = components[1];
    133     root_url += inner_mount_name + "/";
    134     name = inner_mount_name;
    135   } else {
    136     name = id;
    137   }
    138 
    139   callback.Run(GURL(root_url), name, base::File::FILE_OK);
    140 }
    141 
    142 fileapi::FileSystemQuotaUtil* FileSystemBackend::GetQuotaUtil() {
    143   // No quota support.
    144   return NULL;
    145 }
    146 
    147 bool FileSystemBackend::IsAccessAllowed(
    148     const fileapi::FileSystemURL& url) const {
    149   if (!url.is_valid())
    150     return false;
    151 
    152   // No extra check is needed for isolated file systems.
    153   if (url.mount_type() == fileapi::kFileSystemTypeIsolated)
    154     return true;
    155 
    156   if (!CanHandleURL(url))
    157     return false;
    158 
    159   std::string extension_id = url.origin().host();
    160   // TODO(mtomasz): Temporarily whitelist TimeScapes. Remove this in M-31.
    161   // See: crbug.com/271946
    162   if (extension_id == "mlbmkoenclnokonejhlfakkeabdlmpek" &&
    163       url.type() == fileapi::kFileSystemTypeRestrictedNativeLocal) {
    164     return true;
    165   }
    166 
    167   // Check first to make sure this extension has fileBrowserHander permissions.
    168   if (!special_storage_policy_->IsFileHandler(extension_id))
    169     return false;
    170 
    171   return file_access_permissions_->HasAccessPermission(extension_id,
    172                                                        url.virtual_path());
    173 }
    174 
    175 void FileSystemBackend::GrantFullAccessToExtension(
    176     const std::string& extension_id) {
    177   DCHECK(special_storage_policy_->IsFileHandler(extension_id));
    178   if (!special_storage_policy_->IsFileHandler(extension_id))
    179     return;
    180   file_access_permissions_->GrantFullAccessPermission(extension_id);
    181 }
    182 
    183 void FileSystemBackend::GrantFileAccessToExtension(
    184     const std::string& extension_id, const base::FilePath& virtual_path) {
    185   // All we care about here is access from extensions for now.
    186   DCHECK(special_storage_policy_->IsFileHandler(extension_id));
    187   if (!special_storage_policy_->IsFileHandler(extension_id))
    188     return;
    189 
    190   std::string id;
    191   fileapi::FileSystemType type;
    192   std::string cracked_id;
    193   base::FilePath path;
    194   fileapi::FileSystemMountOption option;
    195   if (!mount_points_->CrackVirtualPath(virtual_path, &id, &type, &cracked_id,
    196                                        &path, &option) &&
    197       !system_mount_points_->CrackVirtualPath(virtual_path, &id, &type,
    198                                               &cracked_id, &path, &option)) {
    199     return;
    200   }
    201 
    202   if (type == fileapi::kFileSystemTypeRestrictedNativeLocal) {
    203     LOG(ERROR) << "Can't grant access for restricted mount point";
    204     return;
    205   }
    206 
    207   file_access_permissions_->GrantAccessPermission(extension_id, virtual_path);
    208 }
    209 
    210 void FileSystemBackend::RevokeAccessForExtension(
    211       const std::string& extension_id) {
    212   file_access_permissions_->RevokePermissions(extension_id);
    213 }
    214 
    215 std::vector<base::FilePath> FileSystemBackend::GetRootDirectories() const {
    216   std::vector<fileapi::MountPoints::MountPointInfo> mount_points;
    217   mount_points_->AddMountPointInfosTo(&mount_points);
    218   system_mount_points_->AddMountPointInfosTo(&mount_points);
    219 
    220   std::vector<base::FilePath> root_dirs;
    221   for (size_t i = 0; i < mount_points.size(); ++i)
    222     root_dirs.push_back(mount_points[i].path);
    223   return root_dirs;
    224 }
    225 
    226 fileapi::AsyncFileUtil* FileSystemBackend::GetAsyncFileUtil(
    227     fileapi::FileSystemType type) {
    228   switch (type) {
    229     case fileapi::kFileSystemTypeDrive:
    230       return drive_delegate_->GetAsyncFileUtil(type);
    231     case fileapi::kFileSystemTypeProvided:
    232       return file_system_provider_delegate_->GetAsyncFileUtil(type);
    233     case fileapi::kFileSystemTypeNativeLocal:
    234     case fileapi::kFileSystemTypeRestrictedNativeLocal:
    235       return local_file_util_.get();
    236     case fileapi::kFileSystemTypeDeviceMediaAsFileStorage:
    237       return mtp_delegate_->GetAsyncFileUtil(type);
    238     default:
    239       NOTREACHED();
    240   }
    241   return NULL;
    242 }
    243 
    244 fileapi::CopyOrMoveFileValidatorFactory*
    245 FileSystemBackend::GetCopyOrMoveFileValidatorFactory(
    246     fileapi::FileSystemType type, base::File::Error* error_code) {
    247   DCHECK(error_code);
    248   *error_code = base::File::FILE_OK;
    249   return NULL;
    250 }
    251 
    252 fileapi::FileSystemOperation* FileSystemBackend::CreateFileSystemOperation(
    253     const fileapi::FileSystemURL& url,
    254     fileapi::FileSystemContext* context,
    255     base::File::Error* error_code) const {
    256   DCHECK(url.is_valid());
    257 
    258   if (!IsAccessAllowed(url)) {
    259     *error_code = base::File::FILE_ERROR_SECURITY;
    260     return NULL;
    261   }
    262 
    263   if (url.type() == fileapi::kFileSystemTypeDeviceMediaAsFileStorage) {
    264     // MTP file operations run on MediaTaskRunner.
    265     return fileapi::FileSystemOperation::Create(
    266         url, context,
    267         make_scoped_ptr(new fileapi::FileSystemOperationContext(
    268             context, MediaFileSystemBackend::MediaTaskRunner())));
    269   }
    270 
    271   DCHECK(url.type() == fileapi::kFileSystemTypeNativeLocal ||
    272          url.type() == fileapi::kFileSystemTypeRestrictedNativeLocal ||
    273          url.type() == fileapi::kFileSystemTypeDrive ||
    274          url.type() == fileapi::kFileSystemTypeProvided);
    275   return fileapi::FileSystemOperation::Create(
    276       url, context,
    277       make_scoped_ptr(new fileapi::FileSystemOperationContext(context)));
    278 }
    279 
    280 bool FileSystemBackend::SupportsStreaming(
    281     const fileapi::FileSystemURL& url) const {
    282   return url.type() == fileapi::kFileSystemTypeDrive ||
    283          url.type() == fileapi::kFileSystemTypeProvided ||
    284          url.type() == fileapi::kFileSystemTypeDeviceMediaAsFileStorage;
    285 }
    286 
    287 scoped_ptr<webkit_blob::FileStreamReader>
    288 FileSystemBackend::CreateFileStreamReader(
    289     const fileapi::FileSystemURL& url,
    290     int64 offset,
    291     const base::Time& expected_modification_time,
    292     fileapi::FileSystemContext* context) const {
    293   DCHECK(url.is_valid());
    294 
    295   if (!IsAccessAllowed(url))
    296     return scoped_ptr<webkit_blob::FileStreamReader>();
    297 
    298   switch (url.type()) {
    299     case fileapi::kFileSystemTypeDrive:
    300       return drive_delegate_->CreateFileStreamReader(
    301           url, offset, expected_modification_time, context);
    302     case fileapi::kFileSystemTypeProvided:
    303       return file_system_provider_delegate_->CreateFileStreamReader(
    304           url, offset, expected_modification_time, context);
    305     case fileapi::kFileSystemTypeNativeLocal:
    306     case fileapi::kFileSystemTypeRestrictedNativeLocal:
    307       return scoped_ptr<webkit_blob::FileStreamReader>(
    308           webkit_blob::FileStreamReader::CreateForFileSystemFile(
    309               context, url, offset, expected_modification_time));
    310     case fileapi::kFileSystemTypeDeviceMediaAsFileStorage:
    311       return mtp_delegate_->CreateFileStreamReader(
    312           url, offset, expected_modification_time, context);
    313     default:
    314       NOTREACHED();
    315   }
    316   return scoped_ptr<webkit_blob::FileStreamReader>();
    317 }
    318 
    319 scoped_ptr<fileapi::FileStreamWriter>
    320 FileSystemBackend::CreateFileStreamWriter(
    321     const fileapi::FileSystemURL& url,
    322     int64 offset,
    323     fileapi::FileSystemContext* context) const {
    324   DCHECK(url.is_valid());
    325 
    326   if (!IsAccessAllowed(url))
    327     return scoped_ptr<fileapi::FileStreamWriter>();
    328 
    329   switch (url.type()) {
    330     case fileapi::kFileSystemTypeDrive:
    331       return drive_delegate_->CreateFileStreamWriter(url, offset, context);
    332     case fileapi::kFileSystemTypeProvided:
    333       return file_system_provider_delegate_->CreateFileStreamWriter(
    334           url, offset, context);
    335     case fileapi::kFileSystemTypeNativeLocal:
    336       return scoped_ptr<fileapi::FileStreamWriter>(
    337           fileapi::FileStreamWriter::CreateForLocalFile(
    338               context->default_file_task_runner(), url.path(), offset,
    339               fileapi::FileStreamWriter::OPEN_EXISTING_FILE));
    340     case fileapi::kFileSystemTypeRestrictedNativeLocal:
    341       // Restricted native local file system is read only.
    342       return scoped_ptr<fileapi::FileStreamWriter>();
    343     case fileapi::kFileSystemTypeDeviceMediaAsFileStorage:
    344       return mtp_delegate_->CreateFileStreamWriter(url, offset, context);
    345     default:
    346       NOTREACHED();
    347   }
    348   return scoped_ptr<fileapi::FileStreamWriter>();
    349 }
    350 
    351 bool FileSystemBackend::GetVirtualPath(
    352     const base::FilePath& filesystem_path,
    353     base::FilePath* virtual_path) {
    354   return mount_points_->GetVirtualPath(filesystem_path, virtual_path) ||
    355          system_mount_points_->GetVirtualPath(filesystem_path, virtual_path);
    356 }
    357 
    358 }  // namespace chromeos
    359