Elim cr-checkbox
[chromium-blink-merge.git] / chrome / browser / chromeos / fileapi / file_system_backend.cc
blob242356c027ba1ccc7dfa8a6a143aa71c1231c3a8
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"
27 namespace chromeos {
29 // static
30 bool FileSystemBackend::CanHandleURL(const storage::FileSystemURL& url) {
31 if (!url.is_valid())
32 return false;
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(
63 "archive",
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(
72 "oem",
73 storage::kFileSystemTypeRestrictedNativeLocal,
74 storage::FileSystemMountOption(),
75 base::FilePath(FILE_PATH_LITERAL("/usr/share/oem")));
78 bool FileSystemBackend::CanHandleType(storage::FileSystemType type) const {
79 switch (type) {
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:
87 return true;
88 default:
89 return false;
93 void FileSystemBackend::Initialize(storage::FileSystemContext* context) {
96 void FileSystemBackend::ResolveURL(const storage::FileSystemURL& url,
97 storage::OpenFileSystemMode mode,
98 const OpenFileSystemCallback& callback) {
99 std::string id;
100 storage::FileSystemType type;
101 std::string cracked_id;
102 base::FilePath path;
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
109 // accessible.
110 GURL root_url = GURL(storage::GetExternalFileSystemRootURIString(
111 url.origin(), std::string()));
112 callback.Run(root_url, std::string(), base::File::FILE_ERROR_SECURITY);
113 return;
116 std::string name;
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.
130 callback.Run(
131 GURL(root_url), std::string(), base::File::FILE_ERROR_SECURITY);
132 return;
134 std::string inner_mount_name = components[1];
135 root_url += inner_mount_name + "/";
136 name = inner_mount_name;
137 } else {
138 name = id;
141 callback.Run(GURL(root_url), name, base::File::FILE_OK);
144 storage::FileSystemQuotaUtil* FileSystemBackend::GetQuotaUtil() {
145 // No quota support.
146 return NULL;
149 const storage::UpdateObserverList* FileSystemBackend::GetUpdateObservers(
150 storage::FileSystemType type) const {
151 return NULL;
154 const storage::ChangeObserverList* FileSystemBackend::GetChangeObservers(
155 storage::FileSystemType type) const {
156 return NULL;
159 const storage::AccessObserverList* FileSystemBackend::GetAccessObservers(
160 storage::FileSystemType type) const {
161 return NULL;
164 bool FileSystemBackend::IsAccessAllowed(
165 const storage::FileSystemURL& url) const {
166 if (!url.is_valid())
167 return false;
169 // No extra check is needed for isolated file systems.
170 if (url.mount_type() == storage::kFileSystemTypeIsolated)
171 return true;
173 if (!CanHandleURL(url))
174 return false;
176 // If there is no origin set, then it's an internal access.
177 if (url.origin().is_empty())
178 return true;
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) {
185 return true;
188 return file_access_permissions_->HasAccessPermission(extension_id,
189 url.virtual_path());
192 void FileSystemBackend::GrantFileAccessToExtension(
193 const std::string& extension_id, const base::FilePath& virtual_path) {
194 std::string id;
195 storage::FileSystemType type;
196 std::string cracked_id;
197 base::FilePath path;
198 storage::FileSystemMountOption option;
199 if (!mount_points_->CrackVirtualPath(virtual_path, &id, &type, &cracked_id,
200 &path, &option) &&
201 !system_mount_points_->CrackVirtualPath(virtual_path, &id, &type,
202 &cracked_id, &path, &option)) {
203 return;
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);
222 return root_dirs;
225 storage::AsyncFileUtil* FileSystemBackend::GetAsyncFileUtil(
226 storage::FileSystemType type) {
227 switch (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);
237 default:
238 NOTREACHED();
240 return NULL;
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.
255 return NULL;
258 storage::CopyOrMoveFileValidatorFactory*
259 FileSystemBackend::GetCopyOrMoveFileValidatorFactory(
260 storage::FileSystemType type,
261 base::File::Error* error_code) {
262 DCHECK(error_code);
263 *error_code = base::File::FILE_OK;
264 return NULL;
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;
275 return NULL;
278 if (url.type() == storage::kFileSystemTypeDeviceMediaAsFileStorage) {
279 // MTP file operations run on MediaTaskRunner.
280 return storage::FileSystemOperation::Create(
281 url,
282 context,
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(
292 url,
293 context,
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 {
306 switch (type) {
307 case storage::kFileSystemTypeDrive:
308 case storage::kFileSystemTypeProvided:
309 case storage::kFileSystemTypeDeviceMediaAsFileStorage:
310 return true;
311 case storage::kFileSystemTypeNativeLocal:
312 case storage::kFileSystemTypeRestrictedNativeLocal:
313 return false;
314 default:
315 NOTREACHED();
317 return true;
320 scoped_ptr<storage::FileStreamReader> FileSystemBackend::CreateFileStreamReader(
321 const storage::FileSystemURL& url,
322 int64 offset,
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);
346 default:
347 NOTREACHED();
349 return scoped_ptr<storage::FileStreamReader>();
352 scoped_ptr<storage::FileStreamWriter> FileSystemBackend::CreateFileStreamWriter(
353 const storage::FileSystemURL& url,
354 int64 offset,
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(),
371 url.path(),
372 offset,
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);
379 default:
380 NOTREACHED();
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);
402 return;
403 case storage::kFileSystemTypeProvided:
404 file_system_provider_delegate_->GetRedirectURLForContents(url,
405 callback);
406 return;
407 case storage::kFileSystemTypeDeviceMediaAsFileStorage:
408 mtp_delegate_->GetRedirectURLForContents(url, callback);
409 return;
410 case storage::kFileSystemTypeNativeLocal:
411 case storage::kFileSystemTypeRestrictedNativeLocal:
412 callback.Run(GURL());
413 return;
414 default:
415 NOTREACHED();
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