Update To 11.40.268.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   // Check first to make sure this extension has fileBrowserHander permissions.
185   if (!special_storage_policy_.get() ||
186       !special_storage_policy_->IsFileHandler(extension_id))
187     return false;
188
189   return file_access_permissions_->HasAccessPermission(extension_id,
190                                                        url.virtual_path());
191 }
192
193 void FileSystemBackend::GrantFullAccessToExtension(
194     const std::string& extension_id) {
195   if (!special_storage_policy_.get())
196     return;
197   if (!special_storage_policy_->IsFileHandler(extension_id)) {
198     NOTREACHED();
199     return;
200   }
201   file_access_permissions_->GrantFullAccessPermission(extension_id);
202 }
203
204 void FileSystemBackend::GrantFileAccessToExtension(
205     const std::string& extension_id, const base::FilePath& virtual_path) {
206   if (!special_storage_policy_.get())
207     return;
208   // All we care about here is access from extensions for now.
209   if (!special_storage_policy_->IsFileHandler(extension_id)) {
210     NOTREACHED();
211     return;
212   }
213
214   std::string id;
215   storage::FileSystemType type;
216   std::string cracked_id;
217   base::FilePath path;
218   storage::FileSystemMountOption option;
219   if (!mount_points_->CrackVirtualPath(virtual_path, &id, &type, &cracked_id,
220                                        &path, &option) &&
221       !system_mount_points_->CrackVirtualPath(virtual_path, &id, &type,
222                                               &cracked_id, &path, &option)) {
223     return;
224   }
225
226   if (type == storage::kFileSystemTypeRestrictedNativeLocal) {
227     LOG(ERROR) << "Can't grant access for restricted mount point";
228     return;
229   }
230
231   file_access_permissions_->GrantAccessPermission(extension_id, virtual_path);
232 }
233
234 void FileSystemBackend::RevokeAccessForExtension(
235       const std::string& extension_id) {
236   file_access_permissions_->RevokePermissions(extension_id);
237 }
238
239 std::vector<base::FilePath> FileSystemBackend::GetRootDirectories() const {
240   std::vector<storage::MountPoints::MountPointInfo> mount_points;
241   mount_points_->AddMountPointInfosTo(&mount_points);
242   system_mount_points_->AddMountPointInfosTo(&mount_points);
243
244   std::vector<base::FilePath> root_dirs;
245   for (size_t i = 0; i < mount_points.size(); ++i)
246     root_dirs.push_back(mount_points[i].path);
247   return root_dirs;
248 }
249
250 storage::AsyncFileUtil* FileSystemBackend::GetAsyncFileUtil(
251     storage::FileSystemType type) {
252   switch (type) {
253     case storage::kFileSystemTypeDrive:
254       return drive_delegate_->GetAsyncFileUtil(type);
255     case storage::kFileSystemTypeProvided:
256       return file_system_provider_delegate_->GetAsyncFileUtil(type);
257     case storage::kFileSystemTypeNativeLocal:
258     case storage::kFileSystemTypeRestrictedNativeLocal:
259       return local_file_util_.get();
260     case storage::kFileSystemTypeDeviceMediaAsFileStorage:
261       return mtp_delegate_->GetAsyncFileUtil(type);
262     default:
263       NOTREACHED();
264   }
265   return NULL;
266 }
267
268 storage::WatcherManager* FileSystemBackend::GetWatcherManager(
269     storage::FileSystemType type) {
270   if (type == storage::kFileSystemTypeProvided)
271     return file_system_provider_delegate_->GetWatcherManager(type);
272
273   // TODO(mtomasz): Add support for other backends.
274   return NULL;
275 }
276
277 storage::CopyOrMoveFileValidatorFactory*
278 FileSystemBackend::GetCopyOrMoveFileValidatorFactory(
279     storage::FileSystemType type,
280     base::File::Error* error_code) {
281   DCHECK(error_code);
282   *error_code = base::File::FILE_OK;
283   return NULL;
284 }
285
286 storage::FileSystemOperation* FileSystemBackend::CreateFileSystemOperation(
287     const storage::FileSystemURL& url,
288     storage::FileSystemContext* context,
289     base::File::Error* error_code) const {
290   DCHECK(url.is_valid());
291
292   if (!IsAccessAllowed(url)) {
293     *error_code = base::File::FILE_ERROR_SECURITY;
294     return NULL;
295   }
296
297   if (url.type() == storage::kFileSystemTypeDeviceMediaAsFileStorage) {
298     // MTP file operations run on MediaTaskRunner.
299     return storage::FileSystemOperation::Create(
300         url,
301         context,
302         make_scoped_ptr(new storage::FileSystemOperationContext(
303             context, MediaFileSystemBackend::MediaTaskRunner().get())));
304   }
305
306   DCHECK(url.type() == storage::kFileSystemTypeNativeLocal ||
307          url.type() == storage::kFileSystemTypeRestrictedNativeLocal ||
308          url.type() == storage::kFileSystemTypeDrive ||
309          url.type() == storage::kFileSystemTypeProvided);
310   return storage::FileSystemOperation::Create(
311       url,
312       context,
313       make_scoped_ptr(new storage::FileSystemOperationContext(context)));
314 }
315
316 bool FileSystemBackend::SupportsStreaming(
317     const storage::FileSystemURL& url) const {
318   return url.type() == storage::kFileSystemTypeDrive ||
319          url.type() == storage::kFileSystemTypeProvided ||
320          url.type() == storage::kFileSystemTypeDeviceMediaAsFileStorage;
321 }
322
323 bool FileSystemBackend::HasInplaceCopyImplementation(
324     storage::FileSystemType type) const {
325   switch (type) {
326     case storage::kFileSystemTypeDrive:
327     case storage::kFileSystemTypeProvided:
328     case storage::kFileSystemTypeDeviceMediaAsFileStorage:
329       return true;
330     case storage::kFileSystemTypeNativeLocal:
331     case storage::kFileSystemTypeRestrictedNativeLocal:
332       return false;
333     default:
334       NOTREACHED();
335   }
336   return true;
337 }
338
339 scoped_ptr<storage::FileStreamReader> FileSystemBackend::CreateFileStreamReader(
340     const storage::FileSystemURL& url,
341     int64 offset,
342     int64 max_bytes_to_read,
343     const base::Time& expected_modification_time,
344     storage::FileSystemContext* context) const {
345   DCHECK(url.is_valid());
346
347   if (!IsAccessAllowed(url))
348     return scoped_ptr<storage::FileStreamReader>();
349
350   switch (url.type()) {
351     case storage::kFileSystemTypeDrive:
352       return drive_delegate_->CreateFileStreamReader(
353           url, offset, max_bytes_to_read, expected_modification_time, context);
354     case storage::kFileSystemTypeProvided:
355       return file_system_provider_delegate_->CreateFileStreamReader(
356           url, offset, max_bytes_to_read, expected_modification_time, context);
357     case storage::kFileSystemTypeNativeLocal:
358     case storage::kFileSystemTypeRestrictedNativeLocal:
359       return scoped_ptr<storage::FileStreamReader>(
360           storage::FileStreamReader::CreateForFileSystemFile(
361               context, url, offset, expected_modification_time));
362     case storage::kFileSystemTypeDeviceMediaAsFileStorage:
363       return mtp_delegate_->CreateFileStreamReader(
364           url, offset, max_bytes_to_read, expected_modification_time, context);
365     default:
366       NOTREACHED();
367   }
368   return scoped_ptr<storage::FileStreamReader>();
369 }
370
371 scoped_ptr<storage::FileStreamWriter> FileSystemBackend::CreateFileStreamWriter(
372     const storage::FileSystemURL& url,
373     int64 offset,
374     storage::FileSystemContext* context) const {
375   DCHECK(url.is_valid());
376
377   if (!IsAccessAllowed(url))
378     return scoped_ptr<storage::FileStreamWriter>();
379
380   switch (url.type()) {
381     case storage::kFileSystemTypeDrive:
382       return drive_delegate_->CreateFileStreamWriter(url, offset, context);
383     case storage::kFileSystemTypeProvided:
384       return file_system_provider_delegate_->CreateFileStreamWriter(
385           url, offset, context);
386     case storage::kFileSystemTypeNativeLocal:
387       return scoped_ptr<storage::FileStreamWriter>(
388           storage::FileStreamWriter::CreateForLocalFile(
389               context->default_file_task_runner(),
390               url.path(),
391               offset,
392               storage::FileStreamWriter::OPEN_EXISTING_FILE));
393     case storage::kFileSystemTypeRestrictedNativeLocal:
394       // Restricted native local file system is read only.
395       return scoped_ptr<storage::FileStreamWriter>();
396     case storage::kFileSystemTypeDeviceMediaAsFileStorage:
397       return mtp_delegate_->CreateFileStreamWriter(url, offset, context);
398     default:
399       NOTREACHED();
400   }
401   return scoped_ptr<storage::FileStreamWriter>();
402 }
403
404 bool FileSystemBackend::GetVirtualPath(
405     const base::FilePath& filesystem_path,
406     base::FilePath* virtual_path) {
407   return mount_points_->GetVirtualPath(filesystem_path, virtual_path) ||
408          system_mount_points_->GetVirtualPath(filesystem_path, virtual_path);
409 }
410
411 void FileSystemBackend::GetRedirectURLForContents(
412     const storage::FileSystemURL& url,
413     const storage::URLCallback& callback) {
414   DCHECK(url.is_valid());
415
416   if (!IsAccessAllowed(url))
417     return callback.Run(GURL());
418
419   switch (url.type()) {
420     case storage::kFileSystemTypeDrive:
421       drive_delegate_->GetRedirectURLForContents(url, callback);
422       return;
423     case storage::kFileSystemTypeProvided:
424       file_system_provider_delegate_->GetRedirectURLForContents(url,
425                                                                   callback);
426       return;
427     case storage::kFileSystemTypeDeviceMediaAsFileStorage:
428       mtp_delegate_->GetRedirectURLForContents(url, callback);
429       return;
430     case storage::kFileSystemTypeNativeLocal:
431     case storage::kFileSystemTypeRestrictedNativeLocal:
432       callback.Run(GURL());
433       return;
434     default:
435       NOTREACHED();
436   }
437   callback.Run(GURL());
438 }
439
440 }  // namespace chromeos