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 // Grant access for URL having "externalfile:" scheme. The URL
185 // filesystem:externalfile:/xxx cannot be parsed directly. The URL is created
186 // only by DriveURLRequestJob.
187 if (url
.origin().scheme() == chrome::kExternalFileScheme
)
190 // Check first to make sure this extension has fileBrowserHander permissions.
191 if (!special_storage_policy_
.get() ||
192 !special_storage_policy_
->IsFileHandler(extension_id
))
195 return file_access_permissions_
->HasAccessPermission(extension_id
,
199 void FileSystemBackend::GrantFullAccessToExtension(
200 const std::string
& extension_id
) {
201 if (!special_storage_policy_
.get())
203 if (!special_storage_policy_
->IsFileHandler(extension_id
)) {
207 file_access_permissions_
->GrantFullAccessPermission(extension_id
);
210 void FileSystemBackend::GrantFileAccessToExtension(
211 const std::string
& extension_id
, const base::FilePath
& virtual_path
) {
212 if (!special_storage_policy_
.get())
214 // All we care about here is access from extensions for now.
215 if (!special_storage_policy_
->IsFileHandler(extension_id
)) {
221 storage::FileSystemType type
;
222 std::string cracked_id
;
224 storage::FileSystemMountOption option
;
225 if (!mount_points_
->CrackVirtualPath(virtual_path
, &id
, &type
, &cracked_id
,
227 !system_mount_points_
->CrackVirtualPath(virtual_path
, &id
, &type
,
228 &cracked_id
, &path
, &option
)) {
232 if (type
== storage::kFileSystemTypeRestrictedNativeLocal
) {
233 LOG(ERROR
) << "Can't grant access for restricted mount point";
237 file_access_permissions_
->GrantAccessPermission(extension_id
, virtual_path
);
240 void FileSystemBackend::RevokeAccessForExtension(
241 const std::string
& extension_id
) {
242 file_access_permissions_
->RevokePermissions(extension_id
);
245 std::vector
<base::FilePath
> FileSystemBackend::GetRootDirectories() const {
246 std::vector
<storage::MountPoints::MountPointInfo
> mount_points
;
247 mount_points_
->AddMountPointInfosTo(&mount_points
);
248 system_mount_points_
->AddMountPointInfosTo(&mount_points
);
250 std::vector
<base::FilePath
> root_dirs
;
251 for (size_t i
= 0; i
< mount_points
.size(); ++i
)
252 root_dirs
.push_back(mount_points
[i
].path
);
256 storage::AsyncFileUtil
* FileSystemBackend::GetAsyncFileUtil(
257 storage::FileSystemType type
) {
259 case storage::kFileSystemTypeDrive
:
260 return drive_delegate_
->GetAsyncFileUtil(type
);
261 case storage::kFileSystemTypeProvided
:
262 return file_system_provider_delegate_
->GetAsyncFileUtil(type
);
263 case storage::kFileSystemTypeNativeLocal
:
264 case storage::kFileSystemTypeRestrictedNativeLocal
:
265 return local_file_util_
.get();
266 case storage::kFileSystemTypeDeviceMediaAsFileStorage
:
267 return mtp_delegate_
->GetAsyncFileUtil(type
);
274 storage::WatcherManager
* FileSystemBackend::GetWatcherManager(
275 storage::FileSystemType type
) {
279 storage::CopyOrMoveFileValidatorFactory
*
280 FileSystemBackend::GetCopyOrMoveFileValidatorFactory(
281 storage::FileSystemType type
,
282 base::File::Error
* error_code
) {
284 *error_code
= base::File::FILE_OK
;
288 storage::FileSystemOperation
* FileSystemBackend::CreateFileSystemOperation(
289 const storage::FileSystemURL
& url
,
290 storage::FileSystemContext
* context
,
291 base::File::Error
* error_code
) const {
292 DCHECK(url
.is_valid());
294 if (!IsAccessAllowed(url
)) {
295 *error_code
= base::File::FILE_ERROR_SECURITY
;
299 if (url
.type() == storage::kFileSystemTypeDeviceMediaAsFileStorage
) {
300 // MTP file operations run on MediaTaskRunner.
301 return storage::FileSystemOperation::Create(
304 make_scoped_ptr(new storage::FileSystemOperationContext(
305 context
, MediaFileSystemBackend::MediaTaskRunner().get())));
308 DCHECK(url
.type() == storage::kFileSystemTypeNativeLocal
||
309 url
.type() == storage::kFileSystemTypeRestrictedNativeLocal
||
310 url
.type() == storage::kFileSystemTypeDrive
||
311 url
.type() == storage::kFileSystemTypeProvided
);
312 return storage::FileSystemOperation::Create(
315 make_scoped_ptr(new storage::FileSystemOperationContext(context
)));
318 bool FileSystemBackend::SupportsStreaming(
319 const storage::FileSystemURL
& url
) const {
320 return url
.type() == storage::kFileSystemTypeDrive
||
321 url
.type() == storage::kFileSystemTypeProvided
||
322 url
.type() == storage::kFileSystemTypeDeviceMediaAsFileStorage
;
325 bool FileSystemBackend::HasInplaceCopyImplementation(
326 storage::FileSystemType type
) const {
328 case storage::kFileSystemTypeDrive
:
329 case storage::kFileSystemTypeProvided
:
330 case storage::kFileSystemTypeDeviceMediaAsFileStorage
:
332 case storage::kFileSystemTypeNativeLocal
:
333 case storage::kFileSystemTypeRestrictedNativeLocal
:
341 scoped_ptr
<storage::FileStreamReader
> FileSystemBackend::CreateFileStreamReader(
342 const storage::FileSystemURL
& url
,
344 int64 max_bytes_to_read
,
345 const base::Time
& expected_modification_time
,
346 storage::FileSystemContext
* context
) const {
347 DCHECK(url
.is_valid());
349 if (!IsAccessAllowed(url
))
350 return scoped_ptr
<storage::FileStreamReader
>();
352 switch (url
.type()) {
353 case storage::kFileSystemTypeDrive
:
354 return drive_delegate_
->CreateFileStreamReader(
355 url
, offset
, max_bytes_to_read
, expected_modification_time
, context
);
356 case storage::kFileSystemTypeProvided
:
357 return file_system_provider_delegate_
->CreateFileStreamReader(
358 url
, offset
, max_bytes_to_read
, expected_modification_time
, context
);
359 case storage::kFileSystemTypeNativeLocal
:
360 case storage::kFileSystemTypeRestrictedNativeLocal
:
361 return scoped_ptr
<storage::FileStreamReader
>(
362 storage::FileStreamReader::CreateForFileSystemFile(
363 context
, url
, offset
, expected_modification_time
));
364 case storage::kFileSystemTypeDeviceMediaAsFileStorage
:
365 return mtp_delegate_
->CreateFileStreamReader(
366 url
, offset
, max_bytes_to_read
, expected_modification_time
, context
);
370 return scoped_ptr
<storage::FileStreamReader
>();
373 scoped_ptr
<storage::FileStreamWriter
> FileSystemBackend::CreateFileStreamWriter(
374 const storage::FileSystemURL
& url
,
376 storage::FileSystemContext
* context
) const {
377 DCHECK(url
.is_valid());
379 if (!IsAccessAllowed(url
))
380 return scoped_ptr
<storage::FileStreamWriter
>();
382 switch (url
.type()) {
383 case storage::kFileSystemTypeDrive
:
384 return drive_delegate_
->CreateFileStreamWriter(url
, offset
, context
);
385 case storage::kFileSystemTypeProvided
:
386 return file_system_provider_delegate_
->CreateFileStreamWriter(
387 url
, offset
, context
);
388 case storage::kFileSystemTypeNativeLocal
:
389 return scoped_ptr
<storage::FileStreamWriter
>(
390 storage::FileStreamWriter::CreateForLocalFile(
391 context
->default_file_task_runner(),
394 storage::FileStreamWriter::OPEN_EXISTING_FILE
));
395 case storage::kFileSystemTypeRestrictedNativeLocal
:
396 // Restricted native local file system is read only.
397 return scoped_ptr
<storage::FileStreamWriter
>();
398 case storage::kFileSystemTypeDeviceMediaAsFileStorage
:
399 return mtp_delegate_
->CreateFileStreamWriter(url
, offset
, context
);
403 return scoped_ptr
<storage::FileStreamWriter
>();
406 bool FileSystemBackend::GetVirtualPath(
407 const base::FilePath
& filesystem_path
,
408 base::FilePath
* virtual_path
) {
409 return mount_points_
->GetVirtualPath(filesystem_path
, virtual_path
) ||
410 system_mount_points_
->GetVirtualPath(filesystem_path
, virtual_path
);
413 void FileSystemBackend::GetRedirectURLForContents(
414 const storage::FileSystemURL
& url
,
415 const storage::URLCallback
& callback
) {
416 DCHECK(url
.is_valid());
418 if (!IsAccessAllowed(url
))
419 return callback
.Run(GURL());
421 switch (url
.type()) {
422 case storage::kFileSystemTypeDrive
:
423 drive_delegate_
->GetRedirectURLForContents(url
, callback
);
425 case storage::kFileSystemTypeProvided
:
426 file_system_provider_delegate_
->GetRedirectURLForContents(url
,
429 case storage::kFileSystemTypeDeviceMediaAsFileStorage
:
430 mtp_delegate_
->GetRedirectURLForContents(url
, callback
);
432 case storage::kFileSystemTypeNativeLocal
:
433 case storage::kFileSystemTypeRestrictedNativeLocal
:
434 callback
.Run(GURL());
439 callback
.Run(GURL());
442 } // namespace chromeos