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/command_line.h"
8 #include "base/logging.h"
9 #include "base/memory/scoped_ptr.h"
10 #include "base/strings/stringprintf.h"
11 #include "chrome/browser/chromeos/fileapi/file_access_permissions.h"
12 #include "chrome/browser/chromeos/fileapi/file_system_backend_delegate.h"
13 #include "chrome/browser/media_galleries/fileapi/media_file_system_backend.h"
14 #include "chrome/common/url_constants.h"
15 #include "chromeos/chromeos_switches.h"
16 #include "chromeos/dbus/cros_disks_client.h"
17 #include "storage/browser/fileapi/async_file_util.h"
18 #include "storage/browser/fileapi/external_mount_points.h"
19 #include "storage/browser/fileapi/file_stream_reader.h"
20 #include "storage/browser/fileapi/file_stream_writer.h"
21 #include "storage/browser/fileapi/file_system_context.h"
22 #include "storage/browser/fileapi/file_system_operation.h"
23 #include "storage/browser/fileapi/file_system_operation_context.h"
24 #include "storage/browser/fileapi/file_system_url.h"
25 #include "storage/common/fileapi/file_system_mount_option.h"
30 bool FileSystemBackend::CanHandleURL(const storage::FileSystemURL
& url
) {
33 return url
.type() == storage::kFileSystemTypeNativeLocal
||
34 url
.type() == storage::kFileSystemTypeRestrictedNativeLocal
||
35 url
.type() == storage::kFileSystemTypeDrive
||
36 url
.type() == storage::kFileSystemTypeProvided
||
37 url
.type() == storage::kFileSystemTypeDeviceMediaAsFileStorage
;
40 FileSystemBackend::FileSystemBackend(
41 FileSystemBackendDelegate
* drive_delegate
,
42 FileSystemBackendDelegate
* file_system_provider_delegate
,
43 FileSystemBackendDelegate
* mtp_delegate
,
44 scoped_refptr
<storage::ExternalMountPoints
> mount_points
,
45 storage::ExternalMountPoints
* system_mount_points
)
46 : file_access_permissions_(new FileAccessPermissions()),
47 local_file_util_(storage::AsyncFileUtil::CreateForLocalFileSystem()),
48 drive_delegate_(drive_delegate
),
49 file_system_provider_delegate_(file_system_provider_delegate
),
50 mtp_delegate_(mtp_delegate
),
51 mount_points_(mount_points
),
52 system_mount_points_(system_mount_points
) {
55 FileSystemBackend::~FileSystemBackend() {
58 void FileSystemBackend::AddSystemMountPoints() {
59 // RegisterFileSystem() is no-op if the mount point with the same name
60 // already exists, hence it's safe to call without checking if a mount
61 // point already exists or not.
62 system_mount_points_
->RegisterFileSystem(
64 storage::kFileSystemTypeNativeLocal
,
65 storage::FileSystemMountOption(),
66 chromeos::CrosDisksClient::GetArchiveMountPoint());
67 system_mount_points_
->RegisterFileSystem(
68 "removable", storage::kFileSystemTypeNativeLocal
,
69 storage::FileSystemMountOption(storage::FlushPolicy::FLUSH_ON_COMPLETION
),
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 // If there is no origin set, then it's an internal access.
177 if (url
.origin().is_empty())
180 std::string extension_id
= url
.origin().host();
181 // TODO(mtomasz): Temporarily whitelist TimeScapes. Remove this in M-31.
182 // See: crbug.com/271946
183 if (extension_id
== "mlbmkoenclnokonejhlfakkeabdlmpek" &&
184 url
.type() == storage::kFileSystemTypeRestrictedNativeLocal
) {
188 return file_access_permissions_
->HasAccessPermission(extension_id
,
192 void FileSystemBackend::GrantFileAccessToExtension(
193 const std::string
& extension_id
, const base::FilePath
& virtual_path
) {
195 storage::FileSystemType type
;
196 std::string cracked_id
;
198 storage::FileSystemMountOption option
;
199 if (!mount_points_
->CrackVirtualPath(virtual_path
, &id
, &type
, &cracked_id
,
201 !system_mount_points_
->CrackVirtualPath(virtual_path
, &id
, &type
,
202 &cracked_id
, &path
, &option
)) {
206 file_access_permissions_
->GrantAccessPermission(extension_id
, virtual_path
);
209 void FileSystemBackend::RevokeAccessForExtension(
210 const std::string
& extension_id
) {
211 file_access_permissions_
->RevokePermissions(extension_id
);
214 std::vector
<base::FilePath
> FileSystemBackend::GetRootDirectories() const {
215 std::vector
<storage::MountPoints::MountPointInfo
> mount_points
;
216 mount_points_
->AddMountPointInfosTo(&mount_points
);
217 system_mount_points_
->AddMountPointInfosTo(&mount_points
);
219 std::vector
<base::FilePath
> root_dirs
;
220 for (size_t i
= 0; i
< mount_points
.size(); ++i
)
221 root_dirs
.push_back(mount_points
[i
].path
);
225 storage::AsyncFileUtil
* FileSystemBackend::GetAsyncFileUtil(
226 storage::FileSystemType type
) {
228 case storage::kFileSystemTypeDrive
:
229 return drive_delegate_
->GetAsyncFileUtil(type
);
230 case storage::kFileSystemTypeProvided
:
231 return file_system_provider_delegate_
->GetAsyncFileUtil(type
);
232 case storage::kFileSystemTypeNativeLocal
:
233 case storage::kFileSystemTypeRestrictedNativeLocal
:
234 return local_file_util_
.get();
235 case storage::kFileSystemTypeDeviceMediaAsFileStorage
:
236 return mtp_delegate_
->GetAsyncFileUtil(type
);
243 storage::WatcherManager
* FileSystemBackend::GetWatcherManager(
244 storage::FileSystemType type
) {
245 if (type
== storage::kFileSystemTypeProvided
)
246 return file_system_provider_delegate_
->GetWatcherManager(type
);
248 if (type
== storage::kFileSystemTypeDeviceMediaAsFileStorage
&&
249 !base::CommandLine::ForCurrentProcess()->HasSwitch(
250 chromeos::switches::kDisableMtpWriteSupport
)) {
251 return mtp_delegate_
->GetWatcherManager(type
);
254 // TODO(mtomasz): Add support for other backends.
258 storage::CopyOrMoveFileValidatorFactory
*
259 FileSystemBackend::GetCopyOrMoveFileValidatorFactory(
260 storage::FileSystemType type
,
261 base::File::Error
* error_code
) {
263 *error_code
= base::File::FILE_OK
;
267 storage::FileSystemOperation
* FileSystemBackend::CreateFileSystemOperation(
268 const storage::FileSystemURL
& url
,
269 storage::FileSystemContext
* context
,
270 base::File::Error
* error_code
) const {
271 DCHECK(url
.is_valid());
273 if (!IsAccessAllowed(url
)) {
274 *error_code
= base::File::FILE_ERROR_SECURITY
;
278 if (url
.type() == storage::kFileSystemTypeDeviceMediaAsFileStorage
) {
279 // MTP file operations run on MediaTaskRunner.
280 return storage::FileSystemOperation::Create(
283 make_scoped_ptr(new storage::FileSystemOperationContext(
284 context
, MediaFileSystemBackend::MediaTaskRunner().get())));
287 DCHECK(url
.type() == storage::kFileSystemTypeNativeLocal
||
288 url
.type() == storage::kFileSystemTypeRestrictedNativeLocal
||
289 url
.type() == storage::kFileSystemTypeDrive
||
290 url
.type() == storage::kFileSystemTypeProvided
);
291 return storage::FileSystemOperation::Create(
294 make_scoped_ptr(new storage::FileSystemOperationContext(context
)));
297 bool FileSystemBackend::SupportsStreaming(
298 const storage::FileSystemURL
& url
) const {
299 return url
.type() == storage::kFileSystemTypeDrive
||
300 url
.type() == storage::kFileSystemTypeProvided
||
301 url
.type() == storage::kFileSystemTypeDeviceMediaAsFileStorage
;
304 bool FileSystemBackend::HasInplaceCopyImplementation(
305 storage::FileSystemType type
) const {
307 case storage::kFileSystemTypeDrive
:
308 case storage::kFileSystemTypeProvided
:
309 case storage::kFileSystemTypeDeviceMediaAsFileStorage
:
311 case storage::kFileSystemTypeNativeLocal
:
312 case storage::kFileSystemTypeRestrictedNativeLocal
:
320 scoped_ptr
<storage::FileStreamReader
> FileSystemBackend::CreateFileStreamReader(
321 const storage::FileSystemURL
& url
,
323 int64 max_bytes_to_read
,
324 const base::Time
& expected_modification_time
,
325 storage::FileSystemContext
* context
) const {
326 DCHECK(url
.is_valid());
328 if (!IsAccessAllowed(url
))
329 return scoped_ptr
<storage::FileStreamReader
>();
331 switch (url
.type()) {
332 case storage::kFileSystemTypeDrive
:
333 return drive_delegate_
->CreateFileStreamReader(
334 url
, offset
, max_bytes_to_read
, expected_modification_time
, context
);
335 case storage::kFileSystemTypeProvided
:
336 return file_system_provider_delegate_
->CreateFileStreamReader(
337 url
, offset
, max_bytes_to_read
, expected_modification_time
, context
);
338 case storage::kFileSystemTypeNativeLocal
:
339 case storage::kFileSystemTypeRestrictedNativeLocal
:
340 return scoped_ptr
<storage::FileStreamReader
>(
341 storage::FileStreamReader::CreateForFileSystemFile(
342 context
, url
, offset
, expected_modification_time
));
343 case storage::kFileSystemTypeDeviceMediaAsFileStorage
:
344 return mtp_delegate_
->CreateFileStreamReader(
345 url
, offset
, max_bytes_to_read
, expected_modification_time
, context
);
349 return scoped_ptr
<storage::FileStreamReader
>();
352 scoped_ptr
<storage::FileStreamWriter
> FileSystemBackend::CreateFileStreamWriter(
353 const storage::FileSystemURL
& url
,
355 storage::FileSystemContext
* context
) const {
356 DCHECK(url
.is_valid());
358 if (!IsAccessAllowed(url
))
359 return scoped_ptr
<storage::FileStreamWriter
>();
361 switch (url
.type()) {
362 case storage::kFileSystemTypeDrive
:
363 return drive_delegate_
->CreateFileStreamWriter(url
, offset
, context
);
364 case storage::kFileSystemTypeProvided
:
365 return file_system_provider_delegate_
->CreateFileStreamWriter(
366 url
, offset
, context
);
367 case storage::kFileSystemTypeNativeLocal
:
368 return scoped_ptr
<storage::FileStreamWriter
>(
369 storage::FileStreamWriter::CreateForLocalFile(
370 context
->default_file_task_runner(),
373 storage::FileStreamWriter::OPEN_EXISTING_FILE
));
374 case storage::kFileSystemTypeRestrictedNativeLocal
:
375 // Restricted native local file system is read only.
376 return scoped_ptr
<storage::FileStreamWriter
>();
377 case storage::kFileSystemTypeDeviceMediaAsFileStorage
:
378 return mtp_delegate_
->CreateFileStreamWriter(url
, offset
, context
);
382 return scoped_ptr
<storage::FileStreamWriter
>();
385 bool FileSystemBackend::GetVirtualPath(const base::FilePath
& filesystem_path
,
386 base::FilePath
* virtual_path
) const {
387 return mount_points_
->GetVirtualPath(filesystem_path
, virtual_path
) ||
388 system_mount_points_
->GetVirtualPath(filesystem_path
, virtual_path
);
391 void FileSystemBackend::GetRedirectURLForContents(
392 const storage::FileSystemURL
& url
,
393 const storage::URLCallback
& callback
) const {
394 DCHECK(url
.is_valid());
396 if (!IsAccessAllowed(url
))
397 return callback
.Run(GURL());
399 switch (url
.type()) {
400 case storage::kFileSystemTypeDrive
:
401 drive_delegate_
->GetRedirectURLForContents(url
, callback
);
403 case storage::kFileSystemTypeProvided
:
404 file_system_provider_delegate_
->GetRedirectURLForContents(url
,
407 case storage::kFileSystemTypeDeviceMediaAsFileStorage
:
408 mtp_delegate_
->GetRedirectURLForContents(url
, callback
);
410 case storage::kFileSystemTypeNativeLocal
:
411 case storage::kFileSystemTypeRestrictedNativeLocal
:
412 callback
.Run(GURL());
417 callback
.Run(GURL());
420 storage::FileSystemURL
FileSystemBackend::CreateInternalURL(
421 storage::FileSystemContext
* context
,
422 const base::FilePath
& entry_path
) const {
423 base::FilePath virtual_path
;
424 if (!GetVirtualPath(entry_path
, &virtual_path
))
425 return storage::FileSystemURL();
427 return context
->CreateCrackedFileSystemURL(
428 GURL() /* origin */, storage::kFileSystemTypeExternal
, virtual_path
);
431 } // namespace chromeos