file_system_backend.cc revision 5f1c94371a64b3196d4be9466099bb892df9b88e
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
23namespace chromeos {
24
25// static
26bool 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
36FileSystemBackend::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
52FileSystemBackend::~FileSystemBackend() {
53}
54
55void 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
76bool 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
91void FileSystemBackend::Initialize(fileapi::FileSystemContext* context) {
92}
93
94void 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
142fileapi::FileSystemQuotaUtil* FileSystemBackend::GetQuotaUtil() {
143  // No quota support.
144  return NULL;
145}
146
147bool 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_ ||
169      !special_storage_policy_->IsFileHandler(extension_id))
170    return false;
171
172  return file_access_permissions_->HasAccessPermission(extension_id,
173                                                       url.virtual_path());
174}
175
176void FileSystemBackend::GrantFullAccessToExtension(
177    const std::string& extension_id) {
178  if (!special_storage_policy_)
179    return;
180  if (!special_storage_policy_->IsFileHandler(extension_id)) {
181    NOTREACHED();
182    return;
183  }
184  file_access_permissions_->GrantFullAccessPermission(extension_id);
185}
186
187void FileSystemBackend::GrantFileAccessToExtension(
188    const std::string& extension_id, const base::FilePath& virtual_path) {
189  if (!special_storage_policy_)
190    return;
191  // All we care about here is access from extensions for now.
192  if (!special_storage_policy_->IsFileHandler(extension_id)) {
193    NOTREACHED();
194    return;
195  }
196
197  std::string id;
198  fileapi::FileSystemType type;
199  std::string cracked_id;
200  base::FilePath path;
201  fileapi::FileSystemMountOption option;
202  if (!mount_points_->CrackVirtualPath(virtual_path, &id, &type, &cracked_id,
203                                       &path, &option) &&
204      !system_mount_points_->CrackVirtualPath(virtual_path, &id, &type,
205                                              &cracked_id, &path, &option)) {
206    return;
207  }
208
209  if (type == fileapi::kFileSystemTypeRestrictedNativeLocal) {
210    LOG(ERROR) << "Can't grant access for restricted mount point";
211    return;
212  }
213
214  file_access_permissions_->GrantAccessPermission(extension_id, virtual_path);
215}
216
217void FileSystemBackend::RevokeAccessForExtension(
218      const std::string& extension_id) {
219  file_access_permissions_->RevokePermissions(extension_id);
220}
221
222std::vector<base::FilePath> FileSystemBackend::GetRootDirectories() const {
223  std::vector<fileapi::MountPoints::MountPointInfo> mount_points;
224  mount_points_->AddMountPointInfosTo(&mount_points);
225  system_mount_points_->AddMountPointInfosTo(&mount_points);
226
227  std::vector<base::FilePath> root_dirs;
228  for (size_t i = 0; i < mount_points.size(); ++i)
229    root_dirs.push_back(mount_points[i].path);
230  return root_dirs;
231}
232
233fileapi::AsyncFileUtil* FileSystemBackend::GetAsyncFileUtil(
234    fileapi::FileSystemType type) {
235  switch (type) {
236    case fileapi::kFileSystemTypeDrive:
237      return drive_delegate_->GetAsyncFileUtil(type);
238    case fileapi::kFileSystemTypeProvided:
239      return file_system_provider_delegate_->GetAsyncFileUtil(type);
240    case fileapi::kFileSystemTypeNativeLocal:
241    case fileapi::kFileSystemTypeRestrictedNativeLocal:
242      return local_file_util_.get();
243    case fileapi::kFileSystemTypeDeviceMediaAsFileStorage:
244      return mtp_delegate_->GetAsyncFileUtil(type);
245    default:
246      NOTREACHED();
247  }
248  return NULL;
249}
250
251fileapi::CopyOrMoveFileValidatorFactory*
252FileSystemBackend::GetCopyOrMoveFileValidatorFactory(
253    fileapi::FileSystemType type, base::File::Error* error_code) {
254  DCHECK(error_code);
255  *error_code = base::File::FILE_OK;
256  return NULL;
257}
258
259fileapi::FileSystemOperation* FileSystemBackend::CreateFileSystemOperation(
260    const fileapi::FileSystemURL& url,
261    fileapi::FileSystemContext* context,
262    base::File::Error* error_code) const {
263  DCHECK(url.is_valid());
264
265  if (!IsAccessAllowed(url)) {
266    *error_code = base::File::FILE_ERROR_SECURITY;
267    return NULL;
268  }
269
270  if (url.type() == fileapi::kFileSystemTypeDeviceMediaAsFileStorage) {
271    // MTP file operations run on MediaTaskRunner.
272    return fileapi::FileSystemOperation::Create(
273        url, context,
274        make_scoped_ptr(new fileapi::FileSystemOperationContext(
275            context, MediaFileSystemBackend::MediaTaskRunner())));
276  }
277
278  DCHECK(url.type() == fileapi::kFileSystemTypeNativeLocal ||
279         url.type() == fileapi::kFileSystemTypeRestrictedNativeLocal ||
280         url.type() == fileapi::kFileSystemTypeDrive ||
281         url.type() == fileapi::kFileSystemTypeProvided);
282  return fileapi::FileSystemOperation::Create(
283      url, context,
284      make_scoped_ptr(new fileapi::FileSystemOperationContext(context)));
285}
286
287bool FileSystemBackend::SupportsStreaming(
288    const fileapi::FileSystemURL& url) const {
289  return url.type() == fileapi::kFileSystemTypeDrive ||
290         url.type() == fileapi::kFileSystemTypeProvided ||
291         url.type() == fileapi::kFileSystemTypeDeviceMediaAsFileStorage;
292}
293
294scoped_ptr<webkit_blob::FileStreamReader>
295FileSystemBackend::CreateFileStreamReader(
296    const fileapi::FileSystemURL& url,
297    int64 offset,
298    const base::Time& expected_modification_time,
299    fileapi::FileSystemContext* context) const {
300  DCHECK(url.is_valid());
301
302  if (!IsAccessAllowed(url))
303    return scoped_ptr<webkit_blob::FileStreamReader>();
304
305  switch (url.type()) {
306    case fileapi::kFileSystemTypeDrive:
307      return drive_delegate_->CreateFileStreamReader(
308          url, offset, expected_modification_time, context);
309    case fileapi::kFileSystemTypeProvided:
310      return file_system_provider_delegate_->CreateFileStreamReader(
311          url, offset, expected_modification_time, context);
312    case fileapi::kFileSystemTypeNativeLocal:
313    case fileapi::kFileSystemTypeRestrictedNativeLocal:
314      return scoped_ptr<webkit_blob::FileStreamReader>(
315          webkit_blob::FileStreamReader::CreateForFileSystemFile(
316              context, url, offset, expected_modification_time));
317    case fileapi::kFileSystemTypeDeviceMediaAsFileStorage:
318      return mtp_delegate_->CreateFileStreamReader(
319          url, offset, expected_modification_time, context);
320    default:
321      NOTREACHED();
322  }
323  return scoped_ptr<webkit_blob::FileStreamReader>();
324}
325
326scoped_ptr<fileapi::FileStreamWriter>
327FileSystemBackend::CreateFileStreamWriter(
328    const fileapi::FileSystemURL& url,
329    int64 offset,
330    fileapi::FileSystemContext* context) const {
331  DCHECK(url.is_valid());
332
333  if (!IsAccessAllowed(url))
334    return scoped_ptr<fileapi::FileStreamWriter>();
335
336  switch (url.type()) {
337    case fileapi::kFileSystemTypeDrive:
338      return drive_delegate_->CreateFileStreamWriter(url, offset, context);
339    case fileapi::kFileSystemTypeProvided:
340      return file_system_provider_delegate_->CreateFileStreamWriter(
341          url, offset, context);
342    case fileapi::kFileSystemTypeNativeLocal:
343      return scoped_ptr<fileapi::FileStreamWriter>(
344          fileapi::FileStreamWriter::CreateForLocalFile(
345              context->default_file_task_runner(), url.path(), offset,
346              fileapi::FileStreamWriter::OPEN_EXISTING_FILE));
347    case fileapi::kFileSystemTypeRestrictedNativeLocal:
348      // Restricted native local file system is read only.
349      return scoped_ptr<fileapi::FileStreamWriter>();
350    case fileapi::kFileSystemTypeDeviceMediaAsFileStorage:
351      return mtp_delegate_->CreateFileStreamWriter(url, offset, context);
352    default:
353      NOTREACHED();
354  }
355  return scoped_ptr<fileapi::FileStreamWriter>();
356}
357
358bool FileSystemBackend::GetVirtualPath(
359    const base::FilePath& filesystem_path,
360    base::FilePath* virtual_path) {
361  return mount_points_->GetVirtualPath(filesystem_path, virtual_path) ||
362         system_mount_points_->GetVirtualPath(filesystem_path, virtual_path);
363}
364
365}  // namespace chromeos
366