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.
5 #include "chrome/browser/chromeos/fileapi/file_system_backend.h"
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 "chrome/common/url_constants.h"
14 #include "chromeos/dbus/cros_disks_client.h"
15 #include "storage/browser/blob/file_stream_reader.h"
16 #include "storage/browser/fileapi/async_file_util.h"
17 #include "storage/browser/fileapi/external_mount_points.h"
18 #include "storage/browser/fileapi/file_stream_writer.h"
19 #include "storage/browser/fileapi/file_system_context.h"
20 #include "storage/browser/fileapi/file_system_operation.h"
21 #include "storage/browser/fileapi/file_system_operation_context.h"
22 #include "storage/browser/fileapi/file_system_url.h"
27 bool FileSystemBackend::CanHandleURL(const storage::FileSystemURL& url) {
30 return url.type() == storage::kFileSystemTypeNativeLocal ||
31 url.type() == storage::kFileSystemTypeRestrictedNativeLocal ||
32 url.type() == storage::kFileSystemTypeDrive ||
33 url.type() == storage::kFileSystemTypeProvided ||
34 url.type() == storage::kFileSystemTypeDeviceMediaAsFileStorage;
37 FileSystemBackend::FileSystemBackend(
38 FileSystemBackendDelegate* drive_delegate,
39 FileSystemBackendDelegate* file_system_provider_delegate,
40 FileSystemBackendDelegate* mtp_delegate,
41 scoped_refptr<storage::SpecialStoragePolicy> special_storage_policy,
42 scoped_refptr<storage::ExternalMountPoints> mount_points,
43 storage::ExternalMountPoints* system_mount_points)
44 : special_storage_policy_(special_storage_policy),
45 file_access_permissions_(new FileAccessPermissions()),
46 local_file_util_(storage::AsyncFileUtil::CreateForLocalFileSystem()),
47 drive_delegate_(drive_delegate),
48 file_system_provider_delegate_(file_system_provider_delegate),
49 mtp_delegate_(mtp_delegate),
50 mount_points_(mount_points),
51 system_mount_points_(system_mount_points) {
54 FileSystemBackend::~FileSystemBackend() {
57 void FileSystemBackend::AddSystemMountPoints() {
58 // RegisterFileSystem() is no-op if the mount point with the same name
59 // already exists, hence it's safe to call without checking if a mount
60 // point already exists or not.
61 system_mount_points_->RegisterFileSystem(
63 storage::kFileSystemTypeNativeLocal,
64 storage::FileSystemMountOption(),
65 chromeos::CrosDisksClient::GetArchiveMountPoint());
66 system_mount_points_->RegisterFileSystem(
68 storage::kFileSystemTypeNativeLocal,
69 storage::FileSystemMountOption(storage::COPY_SYNC_OPTION_SYNC),
70 chromeos::CrosDisksClient::GetRemovableDiskMountPoint());
71 system_mount_points_->RegisterFileSystem(
73 storage::kFileSystemTypeRestrictedNativeLocal,
74 storage::FileSystemMountOption(),
75 base::FilePath(FILE_PATH_LITERAL("/usr/share/oem")));
78 bool FileSystemBackend::CanHandleType(storage::FileSystemType type) const {
80 case storage::kFileSystemTypeExternal:
81 case storage::kFileSystemTypeDrive:
82 case storage::kFileSystemTypeRestrictedNativeLocal:
83 case storage::kFileSystemTypeNativeLocal:
84 case storage::kFileSystemTypeNativeForPlatformApp:
85 case storage::kFileSystemTypeDeviceMediaAsFileStorage:
86 case storage::kFileSystemTypeProvided:
93 void FileSystemBackend::Initialize(storage::FileSystemContext* context) {
96 void FileSystemBackend::ResolveURL(const storage::FileSystemURL& url,
97 storage::OpenFileSystemMode mode,
98 const OpenFileSystemCallback& callback) {
100 storage::FileSystemType type;
101 std::string cracked_id;
103 storage::FileSystemMountOption option;
104 if (!mount_points_->CrackVirtualPath(
105 url.virtual_path(), &id, &type, &cracked_id, &path, &option) &&
106 !system_mount_points_->CrackVirtualPath(
107 url.virtual_path(), &id, &type, &cracked_id, &path, &option)) {
108 // Not under a mount point, so return an error, since the root is not
110 GURL root_url = GURL(storage::GetExternalFileSystemRootURIString(
111 url.origin(), std::string()));
112 callback.Run(root_url, std::string(), base::File::FILE_ERROR_SECURITY);
117 // Construct a URL restricted to the found mount point.
118 std::string root_url =
119 storage::GetExternalFileSystemRootURIString(url.origin(), id);
121 // For removable and archives, the file system root is the external mount
122 // point plus the inner mount point.
123 if (id == "archive" || id == "removable") {
124 std::vector<std::string> components;
125 url.virtual_path().GetComponents(&components);
126 DCHECK_EQ(id, components.at(0));
127 if (components.size() < 2) {
128 // Unable to access /archive and /removable directories directly. The
129 // inner mount name must be specified.
131 GURL(root_url), std::string(), base::File::FILE_ERROR_SECURITY);
134 std::string inner_mount_name = components[1];
135 root_url += inner_mount_name + "/";
136 name = inner_mount_name;
141 callback.Run(GURL(root_url), name, base::File::FILE_OK);
144 storage::FileSystemQuotaUtil* FileSystemBackend::GetQuotaUtil() {
149 const storage::UpdateObserverList* FileSystemBackend::GetUpdateObservers(
150 storage::FileSystemType type) const {
154 const storage::ChangeObserverList* FileSystemBackend::GetChangeObservers(
155 storage::FileSystemType type) const {
159 const storage::AccessObserverList* FileSystemBackend::GetAccessObservers(
160 storage::FileSystemType type) const {
164 bool FileSystemBackend::IsAccessAllowed(
165 const storage::FileSystemURL& url) const {
169 // No extra check is needed for isolated file systems.
170 if (url.mount_type() == storage::kFileSystemTypeIsolated)
173 if (!CanHandleURL(url))
176 std::string extension_id = url.origin().host();
177 // TODO(mtomasz): Temporarily whitelist TimeScapes. Remove this in M-31.
178 // See: crbug.com/271946
179 if (extension_id == "mlbmkoenclnokonejhlfakkeabdlmpek" &&
180 url.type() == storage::kFileSystemTypeRestrictedNativeLocal) {
184 // Check first to make sure this extension has fileBrowserHander permissions.
185 if (!special_storage_policy_.get() ||
186 !special_storage_policy_->IsFileHandler(extension_id))
189 return file_access_permissions_->HasAccessPermission(extension_id,
193 void FileSystemBackend::GrantFullAccessToExtension(
194 const std::string& extension_id) {
195 if (!special_storage_policy_.get())
197 if (!special_storage_policy_->IsFileHandler(extension_id)) {
201 file_access_permissions_->GrantFullAccessPermission(extension_id);
204 void FileSystemBackend::GrantFileAccessToExtension(
205 const std::string& extension_id, const base::FilePath& virtual_path) {
206 if (!special_storage_policy_.get())
208 // All we care about here is access from extensions for now.
209 if (!special_storage_policy_->IsFileHandler(extension_id)) {
215 storage::FileSystemType type;
216 std::string cracked_id;
218 storage::FileSystemMountOption option;
219 if (!mount_points_->CrackVirtualPath(virtual_path, &id, &type, &cracked_id,
221 !system_mount_points_->CrackVirtualPath(virtual_path, &id, &type,
222 &cracked_id, &path, &option)) {
226 if (type == storage::kFileSystemTypeRestrictedNativeLocal) {
227 LOG(ERROR) << "Can't grant access for restricted mount point";
231 file_access_permissions_->GrantAccessPermission(extension_id, virtual_path);
234 void FileSystemBackend::RevokeAccessForExtension(
235 const std::string& extension_id) {
236 file_access_permissions_->RevokePermissions(extension_id);
239 std::vector<base::FilePath> FileSystemBackend::GetRootDirectories() const {
240 std::vector<storage::MountPoints::MountPointInfo> mount_points;
241 mount_points_->AddMountPointInfosTo(&mount_points);
242 system_mount_points_->AddMountPointInfosTo(&mount_points);
244 std::vector<base::FilePath> root_dirs;
245 for (size_t i = 0; i < mount_points.size(); ++i)
246 root_dirs.push_back(mount_points[i].path);
250 storage::AsyncFileUtil* FileSystemBackend::GetAsyncFileUtil(
251 storage::FileSystemType type) {
253 case storage::kFileSystemTypeDrive:
254 return drive_delegate_->GetAsyncFileUtil(type);
255 case storage::kFileSystemTypeProvided:
256 return file_system_provider_delegate_->GetAsyncFileUtil(type);
257 case storage::kFileSystemTypeNativeLocal:
258 case storage::kFileSystemTypeRestrictedNativeLocal:
259 return local_file_util_.get();
260 case storage::kFileSystemTypeDeviceMediaAsFileStorage:
261 return mtp_delegate_->GetAsyncFileUtil(type);
268 storage::WatcherManager* FileSystemBackend::GetWatcherManager(
269 storage::FileSystemType type) {
270 if (type == storage::kFileSystemTypeProvided)
271 return file_system_provider_delegate_->GetWatcherManager(type);
273 // TODO(mtomasz): Add support for other backends.
277 storage::CopyOrMoveFileValidatorFactory*
278 FileSystemBackend::GetCopyOrMoveFileValidatorFactory(
279 storage::FileSystemType type,
280 base::File::Error* error_code) {
282 *error_code = base::File::FILE_OK;
286 storage::FileSystemOperation* FileSystemBackend::CreateFileSystemOperation(
287 const storage::FileSystemURL& url,
288 storage::FileSystemContext* context,
289 base::File::Error* error_code) const {
290 DCHECK(url.is_valid());
292 if (!IsAccessAllowed(url)) {
293 *error_code = base::File::FILE_ERROR_SECURITY;
297 if (url.type() == storage::kFileSystemTypeDeviceMediaAsFileStorage) {
298 // MTP file operations run on MediaTaskRunner.
299 return storage::FileSystemOperation::Create(
302 make_scoped_ptr(new storage::FileSystemOperationContext(
303 context, MediaFileSystemBackend::MediaTaskRunner().get())));
306 DCHECK(url.type() == storage::kFileSystemTypeNativeLocal ||
307 url.type() == storage::kFileSystemTypeRestrictedNativeLocal ||
308 url.type() == storage::kFileSystemTypeDrive ||
309 url.type() == storage::kFileSystemTypeProvided);
310 return storage::FileSystemOperation::Create(
313 make_scoped_ptr(new storage::FileSystemOperationContext(context)));
316 bool FileSystemBackend::SupportsStreaming(
317 const storage::FileSystemURL& url) const {
318 return url.type() == storage::kFileSystemTypeDrive ||
319 url.type() == storage::kFileSystemTypeProvided ||
320 url.type() == storage::kFileSystemTypeDeviceMediaAsFileStorage;
323 bool FileSystemBackend::HasInplaceCopyImplementation(
324 storage::FileSystemType type) const {
326 case storage::kFileSystemTypeDrive:
327 case storage::kFileSystemTypeProvided:
328 case storage::kFileSystemTypeDeviceMediaAsFileStorage:
330 case storage::kFileSystemTypeNativeLocal:
331 case storage::kFileSystemTypeRestrictedNativeLocal:
339 scoped_ptr<storage::FileStreamReader> FileSystemBackend::CreateFileStreamReader(
340 const storage::FileSystemURL& url,
342 int64 max_bytes_to_read,
343 const base::Time& expected_modification_time,
344 storage::FileSystemContext* context) const {
345 DCHECK(url.is_valid());
347 if (!IsAccessAllowed(url))
348 return scoped_ptr<storage::FileStreamReader>();
350 switch (url.type()) {
351 case storage::kFileSystemTypeDrive:
352 return drive_delegate_->CreateFileStreamReader(
353 url, offset, max_bytes_to_read, expected_modification_time, context);
354 case storage::kFileSystemTypeProvided:
355 return file_system_provider_delegate_->CreateFileStreamReader(
356 url, offset, max_bytes_to_read, expected_modification_time, context);
357 case storage::kFileSystemTypeNativeLocal:
358 case storage::kFileSystemTypeRestrictedNativeLocal:
359 return scoped_ptr<storage::FileStreamReader>(
360 storage::FileStreamReader::CreateForFileSystemFile(
361 context, url, offset, expected_modification_time));
362 case storage::kFileSystemTypeDeviceMediaAsFileStorage:
363 return mtp_delegate_->CreateFileStreamReader(
364 url, offset, max_bytes_to_read, expected_modification_time, context);
368 return scoped_ptr<storage::FileStreamReader>();
371 scoped_ptr<storage::FileStreamWriter> FileSystemBackend::CreateFileStreamWriter(
372 const storage::FileSystemURL& url,
374 storage::FileSystemContext* context) const {
375 DCHECK(url.is_valid());
377 if (!IsAccessAllowed(url))
378 return scoped_ptr<storage::FileStreamWriter>();
380 switch (url.type()) {
381 case storage::kFileSystemTypeDrive:
382 return drive_delegate_->CreateFileStreamWriter(url, offset, context);
383 case storage::kFileSystemTypeProvided:
384 return file_system_provider_delegate_->CreateFileStreamWriter(
385 url, offset, context);
386 case storage::kFileSystemTypeNativeLocal:
387 return scoped_ptr<storage::FileStreamWriter>(
388 storage::FileStreamWriter::CreateForLocalFile(
389 context->default_file_task_runner(),
392 storage::FileStreamWriter::OPEN_EXISTING_FILE));
393 case storage::kFileSystemTypeRestrictedNativeLocal:
394 // Restricted native local file system is read only.
395 return scoped_ptr<storage::FileStreamWriter>();
396 case storage::kFileSystemTypeDeviceMediaAsFileStorage:
397 return mtp_delegate_->CreateFileStreamWriter(url, offset, context);
401 return scoped_ptr<storage::FileStreamWriter>();
404 bool FileSystemBackend::GetVirtualPath(
405 const base::FilePath& filesystem_path,
406 base::FilePath* virtual_path) {
407 return mount_points_->GetVirtualPath(filesystem_path, virtual_path) ||
408 system_mount_points_->GetVirtualPath(filesystem_path, virtual_path);
411 void FileSystemBackend::GetRedirectURLForContents(
412 const storage::FileSystemURL& url,
413 const storage::URLCallback& callback) {
414 DCHECK(url.is_valid());
416 if (!IsAccessAllowed(url))
417 return callback.Run(GURL());
419 switch (url.type()) {
420 case storage::kFileSystemTypeDrive:
421 drive_delegate_->GetRedirectURLForContents(url, callback);
423 case storage::kFileSystemTypeProvided:
424 file_system_provider_delegate_->GetRedirectURLForContents(url,
427 case storage::kFileSystemTypeDeviceMediaAsFileStorage:
428 mtp_delegate_->GetRedirectURLForContents(url, callback);
430 case storage::kFileSystemTypeNativeLocal:
431 case storage::kFileSystemTypeRestrictedNativeLocal:
432 callback.Run(GURL());
437 callback.Run(GURL());
440 } // namespace chromeos