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 "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"
26 bool FileSystemBackend::CanHandleURL(const fileapi::FileSystemURL& url) {
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;
36 FileSystemBackend::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) {}
52 FileSystemBackend::~FileSystemBackend() {
55 void 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(
61 fileapi::kFileSystemTypeNativeLocal,
62 fileapi::FileSystemMountOption(),
63 chromeos::CrosDisksClient::GetArchiveMountPoint());
64 system_mount_points_->RegisterFileSystem(
66 fileapi::kFileSystemTypeNativeLocal,
67 fileapi::FileSystemMountOption(fileapi::COPY_SYNC_OPTION_SYNC),
68 chromeos::CrosDisksClient::GetRemovableDiskMountPoint());
69 system_mount_points_->RegisterFileSystem(
71 fileapi::kFileSystemTypeRestrictedNativeLocal,
72 fileapi::FileSystemMountOption(),
73 base::FilePath(FILE_PATH_LITERAL("/usr/share/oem")));
76 bool FileSystemBackend::CanHandleType(fileapi::FileSystemType type) const {
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:
91 void FileSystemBackend::Initialize(fileapi::FileSystemContext* context) {
94 void FileSystemBackend::ResolveURL(const fileapi::FileSystemURL& url,
95 fileapi::OpenFileSystemMode mode,
96 const OpenFileSystemCallback& callback) {
98 fileapi::FileSystemType type;
100 fileapi::FileSystemMountOption option;
101 if (!mount_points_->CrackVirtualPath(
102 url.virtual_path(), &id, &type, &path, &option) &&
103 !system_mount_points_->CrackVirtualPath(
104 url.virtual_path(), &id, &type, &path, &option)) {
105 // Not under a mount point, so return an error, since the root is not
107 GURL root_url = GURL(fileapi::GetExternalFileSystemRootURIString(
108 url.origin(), std::string()));
109 callback.Run(root_url, std::string(), base::File::FILE_ERROR_SECURITY);
114 // Construct a URL restricted to the found mount point.
115 std::string root_url =
116 fileapi::GetExternalFileSystemRootURIString(url.origin(), id);
118 // For removable and archives, the file system root is the external mount
119 // point plus the inner mount point.
120 if (id == "archive" || id == "removable") {
121 std::vector<std::string> components;
122 url.virtual_path().GetComponents(&components);
123 DCHECK_EQ(id, components.at(0));
124 if (components.size() < 2) {
125 // Unable to access /archive and /removable directories directly. The
126 // inner mount name must be specified.
128 GURL(root_url), std::string(), base::File::FILE_ERROR_SECURITY);
131 std::string inner_mount_name = components[1];
132 root_url += inner_mount_name + "/";
133 name = inner_mount_name;
138 callback.Run(GURL(root_url), name, base::File::FILE_OK);
141 fileapi::FileSystemQuotaUtil* FileSystemBackend::GetQuotaUtil() {
146 bool FileSystemBackend::IsAccessAllowed(
147 const fileapi::FileSystemURL& url) const {
151 // No extra check is needed for isolated file systems.
152 if (url.mount_type() == fileapi::kFileSystemTypeIsolated)
155 if (!CanHandleURL(url))
158 std::string extension_id = url.origin().host();
159 // TODO(mtomasz): Temporarily whitelist TimeScapes. Remove this in M-31.
160 // See: crbug.com/271946
161 if (extension_id == "mlbmkoenclnokonejhlfakkeabdlmpek" &&
162 url.type() == fileapi::kFileSystemTypeRestrictedNativeLocal) {
166 // Check first to make sure this extension has fileBrowserHander permissions.
167 if (!special_storage_policy_->IsFileHandler(extension_id))
170 return file_access_permissions_->HasAccessPermission(extension_id,
174 void FileSystemBackend::GrantFullAccessToExtension(
175 const std::string& extension_id) {
176 DCHECK(special_storage_policy_->IsFileHandler(extension_id));
177 if (!special_storage_policy_->IsFileHandler(extension_id))
179 file_access_permissions_->GrantFullAccessPermission(extension_id);
182 void FileSystemBackend::GrantFileAccessToExtension(
183 const std::string& extension_id, const base::FilePath& virtual_path) {
184 // All we care about here is access from extensions for now.
185 DCHECK(special_storage_policy_->IsFileHandler(extension_id));
186 if (!special_storage_policy_->IsFileHandler(extension_id))
190 fileapi::FileSystemType type;
192 fileapi::FileSystemMountOption option;
193 if (!mount_points_->CrackVirtualPath(virtual_path,
194 &id, &type, &path, &option) &&
195 !system_mount_points_->CrackVirtualPath(virtual_path,
196 &id, &type, &path, &option)) {
200 if (type == fileapi::kFileSystemTypeRestrictedNativeLocal) {
201 LOG(ERROR) << "Can't grant access for restricted mount point";
205 file_access_permissions_->GrantAccessPermission(extension_id, virtual_path);
208 void FileSystemBackend::RevokeAccessForExtension(
209 const std::string& extension_id) {
210 file_access_permissions_->RevokePermissions(extension_id);
213 std::vector<base::FilePath> FileSystemBackend::GetRootDirectories() const {
214 std::vector<fileapi::MountPoints::MountPointInfo> mount_points;
215 mount_points_->AddMountPointInfosTo(&mount_points);
216 system_mount_points_->AddMountPointInfosTo(&mount_points);
218 std::vector<base::FilePath> root_dirs;
219 for (size_t i = 0; i < mount_points.size(); ++i)
220 root_dirs.push_back(mount_points[i].path);
224 fileapi::AsyncFileUtil* FileSystemBackend::GetAsyncFileUtil(
225 fileapi::FileSystemType type) {
227 case fileapi::kFileSystemTypeDrive:
228 return drive_delegate_->GetAsyncFileUtil(type);
229 case fileapi::kFileSystemTypeProvided:
230 return file_system_provider_delegate_->GetAsyncFileUtil(type);
231 case fileapi::kFileSystemTypeNativeLocal:
232 case fileapi::kFileSystemTypeRestrictedNativeLocal:
233 return local_file_util_.get();
234 case fileapi::kFileSystemTypeDeviceMediaAsFileStorage:
235 return mtp_delegate_->GetAsyncFileUtil(type);
242 fileapi::CopyOrMoveFileValidatorFactory*
243 FileSystemBackend::GetCopyOrMoveFileValidatorFactory(
244 fileapi::FileSystemType type, base::File::Error* error_code) {
246 *error_code = base::File::FILE_OK;
250 fileapi::FileSystemOperation* FileSystemBackend::CreateFileSystemOperation(
251 const fileapi::FileSystemURL& url,
252 fileapi::FileSystemContext* context,
253 base::File::Error* error_code) const {
254 DCHECK(url.is_valid());
256 if (!IsAccessAllowed(url)) {
257 *error_code = base::File::FILE_ERROR_SECURITY;
261 if (url.type() == fileapi::kFileSystemTypeDeviceMediaAsFileStorage) {
262 // MTP file operations run on MediaTaskRunner.
263 return fileapi::FileSystemOperation::Create(
265 make_scoped_ptr(new fileapi::FileSystemOperationContext(
266 context, MediaFileSystemBackend::MediaTaskRunner())));
269 DCHECK(url.type() == fileapi::kFileSystemTypeNativeLocal ||
270 url.type() == fileapi::kFileSystemTypeRestrictedNativeLocal ||
271 url.type() == fileapi::kFileSystemTypeDrive ||
272 url.type() == fileapi::kFileSystemTypeProvided);
273 return fileapi::FileSystemOperation::Create(
275 make_scoped_ptr(new fileapi::FileSystemOperationContext(context)));
278 bool FileSystemBackend::SupportsStreaming(
279 const fileapi::FileSystemURL& url) const {
280 return url.type() == fileapi::kFileSystemTypeDrive;
283 scoped_ptr<webkit_blob::FileStreamReader>
284 FileSystemBackend::CreateFileStreamReader(
285 const fileapi::FileSystemURL& url,
287 const base::Time& expected_modification_time,
288 fileapi::FileSystemContext* context) const {
289 DCHECK(url.is_valid());
291 if (!IsAccessAllowed(url))
292 return scoped_ptr<webkit_blob::FileStreamReader>();
294 switch (url.type()) {
295 case fileapi::kFileSystemTypeDrive:
296 return drive_delegate_->CreateFileStreamReader(
297 url, offset, expected_modification_time, context);
298 case fileapi::kFileSystemTypeProvided:
299 return file_system_provider_delegate_->CreateFileStreamReader(
300 url, offset, expected_modification_time, context);
301 case fileapi::kFileSystemTypeNativeLocal:
302 case fileapi::kFileSystemTypeRestrictedNativeLocal:
303 return scoped_ptr<webkit_blob::FileStreamReader>(
304 webkit_blob::FileStreamReader::CreateForFileSystemFile(
305 context, url, offset, expected_modification_time));
306 case fileapi::kFileSystemTypeDeviceMediaAsFileStorage:
307 return mtp_delegate_->CreateFileStreamReader(
308 url, offset, expected_modification_time, context);
312 return scoped_ptr<webkit_blob::FileStreamReader>();
315 scoped_ptr<fileapi::FileStreamWriter>
316 FileSystemBackend::CreateFileStreamWriter(
317 const fileapi::FileSystemURL& url,
319 fileapi::FileSystemContext* context) const {
320 DCHECK(url.is_valid());
322 if (!IsAccessAllowed(url))
323 return scoped_ptr<fileapi::FileStreamWriter>();
325 switch (url.type()) {
326 case fileapi::kFileSystemTypeDrive:
327 return drive_delegate_->CreateFileStreamWriter(url, offset, context);
328 case fileapi::kFileSystemTypeProvided:
329 return file_system_provider_delegate_->CreateFileStreamWriter(
330 url, offset, context);
331 case fileapi::kFileSystemTypeNativeLocal:
332 return scoped_ptr<fileapi::FileStreamWriter>(
333 fileapi::FileStreamWriter::CreateForLocalFile(
334 context->default_file_task_runner(), url.path(), offset,
335 fileapi::FileStreamWriter::OPEN_EXISTING_FILE));
336 case fileapi::kFileSystemTypeRestrictedNativeLocal:
337 // Restricted native local file system is read only.
338 return scoped_ptr<fileapi::FileStreamWriter>();
339 case fileapi::kFileSystemTypeDeviceMediaAsFileStorage:
340 return mtp_delegate_->CreateFileStreamWriter(url, offset, context);
344 return scoped_ptr<fileapi::FileStreamWriter>();
347 bool FileSystemBackend::GetVirtualPath(
348 const base::FilePath& filesystem_path,
349 base::FilePath* virtual_path) {
350 return mount_points_->GetVirtualPath(filesystem_path, virtual_path) ||
351 system_mount_points_->GetVirtualPath(filesystem_path, virtual_path);
354 } // namespace chromeos