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