root/chrome/browser/chromeos/fileapi/file_system_backend.cc

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. CanHandleURL
  2. system_mount_points_
  3. AddSystemMountPoints
  4. CanHandleType
  5. Initialize
  6. ResolveURL
  7. GetQuotaUtil
  8. IsAccessAllowed
  9. GrantFullAccessToExtension
  10. GrantFileAccessToExtension
  11. RevokeAccessForExtension
  12. GetRootDirectories
  13. GetAsyncFileUtil
  14. GetCopyOrMoveFileValidatorFactory
  15. CreateFileSystemOperation
  16. SupportsStreaming
  17. CreateFileStreamReader
  18. CreateFileStreamWriter
  19. GetVirtualPath

// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/chromeos/fileapi/file_system_backend.h"

#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
#include "base/message_loop/message_loop.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "base/synchronization/lock.h"
#include "chrome/browser/chromeos/fileapi/file_access_permissions.h"
#include "chrome/browser/chromeos/fileapi/file_system_backend_delegate.h"
#include "chromeos/dbus/cros_disks_client.h"
#include "webkit/browser/blob/file_stream_reader.h"
#include "webkit/browser/fileapi/async_file_util.h"
#include "webkit/browser/fileapi/external_mount_points.h"
#include "webkit/browser/fileapi/file_stream_writer.h"
#include "webkit/browser/fileapi/file_system_context.h"
#include "webkit/browser/fileapi/file_system_operation.h"
#include "webkit/browser/fileapi/file_system_operation_context.h"
#include "webkit/browser/fileapi/file_system_url.h"
#include "webkit/browser/fileapi/isolated_context.h"

namespace {

const char kChromeUIScheme[] = "chrome";

}  // namespace

namespace chromeos {

// static
bool FileSystemBackend::CanHandleURL(const fileapi::FileSystemURL& url) {
  if (!url.is_valid())
    return false;
  return url.type() == fileapi::kFileSystemTypeNativeLocal ||
         url.type() == fileapi::kFileSystemTypeRestrictedNativeLocal ||
         url.type() == fileapi::kFileSystemTypeDrive;
}

FileSystemBackend::FileSystemBackend(
    FileSystemBackendDelegate* drive_delegate,
    scoped_refptr<quota::SpecialStoragePolicy> special_storage_policy,
    scoped_refptr<fileapi::ExternalMountPoints> mount_points,
    fileapi::ExternalMountPoints* system_mount_points)
    : special_storage_policy_(special_storage_policy),
      file_access_permissions_(new FileAccessPermissions()),
      local_file_util_(fileapi::AsyncFileUtil::CreateForLocalFileSystem()),
      drive_delegate_(drive_delegate),
      mount_points_(mount_points),
      system_mount_points_(system_mount_points) {
}

FileSystemBackend::~FileSystemBackend() {
}

void FileSystemBackend::AddSystemMountPoints() {
  // RegisterFileSystem() is no-op if the mount point with the same name
  // already exists, hence it's safe to call without checking if a mount
  // point already exists or not.
  system_mount_points_->RegisterFileSystem(
      "archive",
      fileapi::kFileSystemTypeNativeLocal,
      fileapi::FileSystemMountOption(),
      chromeos::CrosDisksClient::GetArchiveMountPoint());
  system_mount_points_->RegisterFileSystem(
      "removable",
      fileapi::kFileSystemTypeNativeLocal,
      fileapi::FileSystemMountOption(fileapi::COPY_SYNC_OPTION_SYNC),
      chromeos::CrosDisksClient::GetRemovableDiskMountPoint());
  system_mount_points_->RegisterFileSystem(
      "oem",
      fileapi::kFileSystemTypeRestrictedNativeLocal,
      fileapi::FileSystemMountOption(),
      base::FilePath(FILE_PATH_LITERAL("/usr/share/oem")));
}

bool FileSystemBackend::CanHandleType(fileapi::FileSystemType type) const {
  switch (type) {
    case fileapi::kFileSystemTypeExternal:
    case fileapi::kFileSystemTypeDrive:
    case fileapi::kFileSystemTypeRestrictedNativeLocal:
    case fileapi::kFileSystemTypeNativeLocal:
    case fileapi::kFileSystemTypeNativeForPlatformApp:
      return true;
    default:
      return false;
  }
}

void FileSystemBackend::Initialize(fileapi::FileSystemContext* context) {
}

void FileSystemBackend::ResolveURL(const fileapi::FileSystemURL& url,
                                   fileapi::OpenFileSystemMode mode,
                                   const OpenFileSystemCallback& callback) {
  std::string id;
  fileapi::FileSystemType type;
  base::FilePath path;
  fileapi::FileSystemMountOption option;
  if (!mount_points_->CrackVirtualPath(
           url.virtual_path(), &id, &type, &path, &option) &&
      !system_mount_points_->CrackVirtualPath(
           url.virtual_path(), &id, &type, &path, &option)) {
    // Not under a mount point, so return an error, since the root is not
    // accessible.
    GURL root_url = GURL(fileapi::GetExternalFileSystemRootURIString(
        url.origin(), std::string()));
    callback.Run(root_url, std::string(), base::File::FILE_ERROR_SECURITY);
    return;
  }

  std::string name;
  // Construct a URL restricted to the found mount point.
  std::string root_url =
      fileapi::GetExternalFileSystemRootURIString(url.origin(), id);

  // For removable and archives, the file system root is the external mount
  // point plus the inner mount point.
  if (id == "archive" || id == "removable") {
    std::vector<std::string> components;
    url.virtual_path().GetComponents(&components);
    DCHECK_EQ(id, components.at(0));
    if (components.size() < 2) {
      // Unable to access /archive and /removable directories directly. The
      // inner mount name must be specified.
      callback.Run(
          GURL(root_url), std::string(), base::File::FILE_ERROR_SECURITY);
      return;
    }
    std::string inner_mount_name = components[1];
    root_url += inner_mount_name + "/";
    name = inner_mount_name;
  } else {
    name = id;
  }

  callback.Run(GURL(root_url), name, base::File::FILE_OK);
}

fileapi::FileSystemQuotaUtil* FileSystemBackend::GetQuotaUtil() {
  // No quota support.
  return NULL;
}

bool FileSystemBackend::IsAccessAllowed(
    const fileapi::FileSystemURL& url) const {
  if (!url.is_valid())
    return false;

  // Permit access to mount points from internal WebUI.
  const GURL& origin_url = url.origin();
  if (origin_url.SchemeIs(kChromeUIScheme))
    return true;

  // No extra check is needed for isolated file systems.
  if (url.mount_type() == fileapi::kFileSystemTypeIsolated)
    return true;

  if (!CanHandleURL(url))
    return false;

  std::string extension_id = origin_url.host();
  // TODO(mtomasz): Temporarily whitelist TimeScapes. Remove this in M-31.
  // See: crbug.com/271946
  if (extension_id == "mlbmkoenclnokonejhlfakkeabdlmpek" &&
      url.type() == fileapi::kFileSystemTypeRestrictedNativeLocal) {
    return true;
  }

  // Check first to make sure this extension has fileBrowserHander permissions.
  if (!special_storage_policy_->IsFileHandler(extension_id))
    return false;

  return file_access_permissions_->HasAccessPermission(extension_id,
                                                       url.virtual_path());
}

void FileSystemBackend::GrantFullAccessToExtension(
    const std::string& extension_id) {
  DCHECK(special_storage_policy_->IsFileHandler(extension_id));
  if (!special_storage_policy_->IsFileHandler(extension_id))
    return;
  file_access_permissions_->GrantFullAccessPermission(extension_id);
}

void FileSystemBackend::GrantFileAccessToExtension(
    const std::string& extension_id, const base::FilePath& virtual_path) {
  // All we care about here is access from extensions for now.
  DCHECK(special_storage_policy_->IsFileHandler(extension_id));
  if (!special_storage_policy_->IsFileHandler(extension_id))
    return;

  std::string id;
  fileapi::FileSystemType type;
  base::FilePath path;
  fileapi::FileSystemMountOption option;
  if (!mount_points_->CrackVirtualPath(virtual_path,
                                       &id, &type, &path, &option) &&
      !system_mount_points_->CrackVirtualPath(virtual_path,
                                              &id, &type, &path, &option)) {
    return;
  }

  if (type == fileapi::kFileSystemTypeRestrictedNativeLocal) {
    LOG(ERROR) << "Can't grant access for restricted mount point";
    return;
  }

  file_access_permissions_->GrantAccessPermission(extension_id, virtual_path);
}

void FileSystemBackend::RevokeAccessForExtension(
      const std::string& extension_id) {
  file_access_permissions_->RevokePermissions(extension_id);
}

std::vector<base::FilePath> FileSystemBackend::GetRootDirectories() const {
  std::vector<fileapi::MountPoints::MountPointInfo> mount_points;
  mount_points_->AddMountPointInfosTo(&mount_points);
  system_mount_points_->AddMountPointInfosTo(&mount_points);

  std::vector<base::FilePath> root_dirs;
  for (size_t i = 0; i < mount_points.size(); ++i)
    root_dirs.push_back(mount_points[i].path);
  return root_dirs;
}

fileapi::AsyncFileUtil* FileSystemBackend::GetAsyncFileUtil(
    fileapi::FileSystemType type) {
  if (type == fileapi::kFileSystemTypeDrive)
    return drive_delegate_->GetAsyncFileUtil(type);

  DCHECK(type == fileapi::kFileSystemTypeNativeLocal ||
         type == fileapi::kFileSystemTypeRestrictedNativeLocal);
  return local_file_util_.get();
}

fileapi::CopyOrMoveFileValidatorFactory*
FileSystemBackend::GetCopyOrMoveFileValidatorFactory(
    fileapi::FileSystemType type, base::File::Error* error_code) {
  DCHECK(error_code);
  *error_code = base::File::FILE_OK;
  return NULL;
}

fileapi::FileSystemOperation* FileSystemBackend::CreateFileSystemOperation(
    const fileapi::FileSystemURL& url,
    fileapi::FileSystemContext* context,
    base::File::Error* error_code) const {
  DCHECK(url.is_valid());

  if (!IsAccessAllowed(url)) {
    *error_code = base::File::FILE_ERROR_SECURITY;
    return NULL;
  }

  DCHECK(url.type() == fileapi::kFileSystemTypeNativeLocal ||
         url.type() == fileapi::kFileSystemTypeRestrictedNativeLocal ||
         url.type() == fileapi::kFileSystemTypeDrive);
  return fileapi::FileSystemOperation::Create(
      url, context,
      make_scoped_ptr(new fileapi::FileSystemOperationContext(context)));
}

bool FileSystemBackend::SupportsStreaming(
    const fileapi::FileSystemURL& url) const {
  return false;
}

scoped_ptr<webkit_blob::FileStreamReader>
FileSystemBackend::CreateFileStreamReader(
    const fileapi::FileSystemURL& url,
    int64 offset,
    const base::Time& expected_modification_time,
    fileapi::FileSystemContext* context) const {
  DCHECK(url.is_valid());

  if (!IsAccessAllowed(url))
    return scoped_ptr<webkit_blob::FileStreamReader>();

  if (url.type() == fileapi::kFileSystemTypeDrive) {
    return drive_delegate_->CreateFileStreamReader(
        url, offset, expected_modification_time, context);
  }

  return scoped_ptr<webkit_blob::FileStreamReader>(
      webkit_blob::FileStreamReader::CreateForFileSystemFile(
          context, url, offset, expected_modification_time));
}

scoped_ptr<fileapi::FileStreamWriter>
FileSystemBackend::CreateFileStreamWriter(
    const fileapi::FileSystemURL& url,
    int64 offset,
    fileapi::FileSystemContext* context) const {
  DCHECK(url.is_valid());

  if (!IsAccessAllowed(url))
    return scoped_ptr<fileapi::FileStreamWriter>();

  if (url.type() == fileapi::kFileSystemTypeDrive)
    return drive_delegate_->CreateFileStreamWriter(url, offset, context);

  if (url.type() == fileapi::kFileSystemTypeRestrictedNativeLocal)
    return scoped_ptr<fileapi::FileStreamWriter>();

  DCHECK(url.type() == fileapi::kFileSystemTypeNativeLocal);
  return scoped_ptr<fileapi::FileStreamWriter>(
      fileapi::FileStreamWriter::CreateForLocalFile(
          context->default_file_task_runner(), url.path(), offset,
          fileapi::FileStreamWriter::OPEN_EXISTING_FILE));
}

bool FileSystemBackend::GetVirtualPath(
    const base::FilePath& filesystem_path,
    base::FilePath* virtual_path) {
  return mount_points_->GetVirtualPath(filesystem_path, virtual_path) ||
         system_mount_points_->GetVirtualPath(filesystem_path, virtual_path);
}

}  // namespace chromeos

/* [<][>][^][v][top][bottom][index][help] */