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