Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / chromeos / fileapi / file_system_backend.cc
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 "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"
23
24 namespace chromeos {
25
26 // static
27 bool FileSystemBackend::CanHandleURL(const storage::FileSystemURL& url) {
28   if (!url.is_valid())
29     return false;
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;
35 }
36
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) {
52 }
53
54 FileSystemBackend::~FileSystemBackend() {
55 }
56
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(
62       "archive",
63       storage::kFileSystemTypeNativeLocal,
64       storage::FileSystemMountOption(),
65       chromeos::CrosDisksClient::GetArchiveMountPoint());
66   system_mount_points_->RegisterFileSystem(
67       "removable",
68       storage::kFileSystemTypeNativeLocal,
69       storage::FileSystemMountOption(storage::COPY_SYNC_OPTION_SYNC),
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")));
76 }
77
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;
90   }
91 }
92
93 void FileSystemBackend::Initialize(storage::FileSystemContext* context) {
94 }
95
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;
114   }
115
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);
120
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;
133     }
134     std::string inner_mount_name = components[1];
135     root_url += inner_mount_name + "/";
136     name = inner_mount_name;
137   } else {
138     name = id;
139   }
140
141   callback.Run(GURL(root_url), name, base::File::FILE_OK);
142 }
143
144 storage::FileSystemQuotaUtil* FileSystemBackend::GetQuotaUtil() {
145   // No quota support.
146   return NULL;
147 }
148
149 const storage::UpdateObserverList* FileSystemBackend::GetUpdateObservers(
150     storage::FileSystemType type) const {
151   return NULL;
152 }
153
154 const storage::ChangeObserverList* FileSystemBackend::GetChangeObservers(
155     storage::FileSystemType type) const {
156   return NULL;
157 }
158
159 const storage::AccessObserverList* FileSystemBackend::GetAccessObservers(
160     storage::FileSystemType type) const {
161   return NULL;
162 }
163
164 bool FileSystemBackend::IsAccessAllowed(
165     const storage::FileSystemURL& url) const {
166   if (!url.is_valid())
167     return false;
168
169   // No extra check is needed for isolated file systems.
170   if (url.mount_type() == storage::kFileSystemTypeIsolated)
171     return true;
172
173   if (!CanHandleURL(url))
174     return false;
175
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) {
181     return true;
182   }
183
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)
188     return true;
189
190   // Check first to make sure this extension has fileBrowserHander permissions.
191   if (!special_storage_policy_.get() ||
192       !special_storage_policy_->IsFileHandler(extension_id))
193     return false;
194
195   return file_access_permissions_->HasAccessPermission(extension_id,
196                                                        url.virtual_path());
197 }
198
199 void FileSystemBackend::GrantFullAccessToExtension(
200     const std::string& extension_id) {
201   if (!special_storage_policy_.get())
202     return;
203   if (!special_storage_policy_->IsFileHandler(extension_id)) {
204     NOTREACHED();
205     return;
206   }
207   file_access_permissions_->GrantFullAccessPermission(extension_id);
208 }
209
210 void FileSystemBackend::GrantFileAccessToExtension(
211     const std::string& extension_id, const base::FilePath& virtual_path) {
212   if (!special_storage_policy_.get())
213     return;
214   // All we care about here is access from extensions for now.
215   if (!special_storage_policy_->IsFileHandler(extension_id)) {
216     NOTREACHED();
217     return;
218   }
219
220   std::string id;
221   storage::FileSystemType type;
222   std::string cracked_id;
223   base::FilePath path;
224   storage::FileSystemMountOption option;
225   if (!mount_points_->CrackVirtualPath(virtual_path, &id, &type, &cracked_id,
226                                        &path, &option) &&
227       !system_mount_points_->CrackVirtualPath(virtual_path, &id, &type,
228                                               &cracked_id, &path, &option)) {
229     return;
230   }
231
232   if (type == storage::kFileSystemTypeRestrictedNativeLocal) {
233     LOG(ERROR) << "Can't grant access for restricted mount point";
234     return;
235   }
236
237   file_access_permissions_->GrantAccessPermission(extension_id, virtual_path);
238 }
239
240 void FileSystemBackend::RevokeAccessForExtension(
241       const std::string& extension_id) {
242   file_access_permissions_->RevokePermissions(extension_id);
243 }
244
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);
249
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);
253   return root_dirs;
254 }
255
256 storage::AsyncFileUtil* FileSystemBackend::GetAsyncFileUtil(
257     storage::FileSystemType type) {
258   switch (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);
268     default:
269       NOTREACHED();
270   }
271   return NULL;
272 }
273
274 storage::WatcherManager* FileSystemBackend::GetWatcherManager(
275     storage::FileSystemType type) {
276   return NULL;
277 }
278
279 storage::CopyOrMoveFileValidatorFactory*
280 FileSystemBackend::GetCopyOrMoveFileValidatorFactory(
281     storage::FileSystemType type,
282     base::File::Error* error_code) {
283   DCHECK(error_code);
284   *error_code = base::File::FILE_OK;
285   return NULL;
286 }
287
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());
293
294   if (!IsAccessAllowed(url)) {
295     *error_code = base::File::FILE_ERROR_SECURITY;
296     return NULL;
297   }
298
299   if (url.type() == storage::kFileSystemTypeDeviceMediaAsFileStorage) {
300     // MTP file operations run on MediaTaskRunner.
301     return storage::FileSystemOperation::Create(
302         url,
303         context,
304         make_scoped_ptr(new storage::FileSystemOperationContext(
305             context, MediaFileSystemBackend::MediaTaskRunner().get())));
306   }
307
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(
313       url,
314       context,
315       make_scoped_ptr(new storage::FileSystemOperationContext(context)));
316 }
317
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;
323 }
324
325 bool FileSystemBackend::HasInplaceCopyImplementation(
326     storage::FileSystemType type) const {
327   switch (type) {
328     case storage::kFileSystemTypeDrive:
329     case storage::kFileSystemTypeProvided:
330     case storage::kFileSystemTypeDeviceMediaAsFileStorage:
331       return true;
332     case storage::kFileSystemTypeNativeLocal:
333     case storage::kFileSystemTypeRestrictedNativeLocal:
334       return false;
335     default:
336       NOTREACHED();
337   }
338   return true;
339 }
340
341 scoped_ptr<storage::FileStreamReader> FileSystemBackend::CreateFileStreamReader(
342     const storage::FileSystemURL& url,
343     int64 offset,
344     int64 max_bytes_to_read,
345     const base::Time& expected_modification_time,
346     storage::FileSystemContext* context) const {
347   DCHECK(url.is_valid());
348
349   if (!IsAccessAllowed(url))
350     return scoped_ptr<storage::FileStreamReader>();
351
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);
367     default:
368       NOTREACHED();
369   }
370   return scoped_ptr<storage::FileStreamReader>();
371 }
372
373 scoped_ptr<storage::FileStreamWriter> FileSystemBackend::CreateFileStreamWriter(
374     const storage::FileSystemURL& url,
375     int64 offset,
376     storage::FileSystemContext* context) const {
377   DCHECK(url.is_valid());
378
379   if (!IsAccessAllowed(url))
380     return scoped_ptr<storage::FileStreamWriter>();
381
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(),
392               url.path(),
393               offset,
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);
400     default:
401       NOTREACHED();
402   }
403   return scoped_ptr<storage::FileStreamWriter>();
404 }
405
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);
411 }
412
413 void FileSystemBackend::GetRedirectURLForContents(
414     const storage::FileSystemURL& url,
415     const storage::URLCallback& callback) {
416   DCHECK(url.is_valid());
417
418   if (!IsAccessAllowed(url))
419     return callback.Run(GURL());
420
421   switch (url.type()) {
422     case storage::kFileSystemTypeDrive:
423       drive_delegate_->GetRedirectURLForContents(url, callback);
424       return;
425     case storage::kFileSystemTypeProvided:
426       file_system_provider_delegate_->GetRedirectURLForContents(url,
427                                                                   callback);
428       return;
429     case storage::kFileSystemTypeDeviceMediaAsFileStorage:
430       mtp_delegate_->GetRedirectURLForContents(url, callback);
431       return;
432     case storage::kFileSystemTypeNativeLocal:
433     case storage::kFileSystemTypeRestrictedNativeLocal:
434       callback.Run(GURL());
435       return;
436     default:
437       NOTREACHED();
438   }
439   callback.Run(GURL());
440 }
441
442 }  // namespace chromeos