Upstream version 7.36.149.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 "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
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
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
52 FileSystemBackend::~FileSystemBackend() {
53 }
54
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
76 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
91 void FileSystemBackend::Initialize(fileapi::FileSystemContext* context) {
92 }
93
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   base::FilePath path;
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
106     // accessible.
107     GURL root_url = GURL(fileapi::GetExternalFileSystemRootURIString(
108         url.origin(), std::string()));
109     callback.Run(root_url, std::string(), base::File::FILE_ERROR_SECURITY);
110     return;
111   }
112
113   std::string name;
114   // Construct a URL restricted to the found mount point.
115   std::string root_url =
116       fileapi::GetExternalFileSystemRootURIString(url.origin(), id);
117
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.
127       callback.Run(
128           GURL(root_url), std::string(), base::File::FILE_ERROR_SECURITY);
129       return;
130     }
131     std::string inner_mount_name = components[1];
132     root_url += inner_mount_name + "/";
133     name = inner_mount_name;
134   } else {
135     name = id;
136   }
137
138   callback.Run(GURL(root_url), name, base::File::FILE_OK);
139 }
140
141 fileapi::FileSystemQuotaUtil* FileSystemBackend::GetQuotaUtil() {
142   // No quota support.
143   return NULL;
144 }
145
146 bool FileSystemBackend::IsAccessAllowed(
147     const fileapi::FileSystemURL& url) const {
148   if (!url.is_valid())
149     return false;
150
151   // No extra check is needed for isolated file systems.
152   if (url.mount_type() == fileapi::kFileSystemTypeIsolated)
153     return true;
154
155   if (!CanHandleURL(url))
156     return false;
157
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) {
163     return true;
164   }
165
166   // Check first to make sure this extension has fileBrowserHander permissions.
167   if (!special_storage_policy_->IsFileHandler(extension_id))
168     return false;
169
170   return file_access_permissions_->HasAccessPermission(extension_id,
171                                                        url.virtual_path());
172 }
173
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))
178     return;
179   file_access_permissions_->GrantFullAccessPermission(extension_id);
180 }
181
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))
187     return;
188
189   std::string id;
190   fileapi::FileSystemType type;
191   base::FilePath path;
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)) {
197     return;
198   }
199
200   if (type == fileapi::kFileSystemTypeRestrictedNativeLocal) {
201     LOG(ERROR) << "Can't grant access for restricted mount point";
202     return;
203   }
204
205   file_access_permissions_->GrantAccessPermission(extension_id, virtual_path);
206 }
207
208 void FileSystemBackend::RevokeAccessForExtension(
209       const std::string& extension_id) {
210   file_access_permissions_->RevokePermissions(extension_id);
211 }
212
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);
217
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);
221   return root_dirs;
222 }
223
224 fileapi::AsyncFileUtil* FileSystemBackend::GetAsyncFileUtil(
225     fileapi::FileSystemType type) {
226   switch (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);
236     default:
237       NOTREACHED();
238   }
239   return NULL;
240 }
241
242 fileapi::CopyOrMoveFileValidatorFactory*
243 FileSystemBackend::GetCopyOrMoveFileValidatorFactory(
244     fileapi::FileSystemType type, base::File::Error* error_code) {
245   DCHECK(error_code);
246   *error_code = base::File::FILE_OK;
247   return NULL;
248 }
249
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());
255
256   if (!IsAccessAllowed(url)) {
257     *error_code = base::File::FILE_ERROR_SECURITY;
258     return NULL;
259   }
260
261   if (url.type() == fileapi::kFileSystemTypeDeviceMediaAsFileStorage) {
262     // MTP file operations run on MediaTaskRunner.
263     return fileapi::FileSystemOperation::Create(
264         url, context,
265         make_scoped_ptr(new fileapi::FileSystemOperationContext(
266             context, MediaFileSystemBackend::MediaTaskRunner())));
267   }
268
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(
274       url, context,
275       make_scoped_ptr(new fileapi::FileSystemOperationContext(context)));
276 }
277
278 bool FileSystemBackend::SupportsStreaming(
279     const fileapi::FileSystemURL& url) const {
280   return url.type() == fileapi::kFileSystemTypeDrive;
281 }
282
283 scoped_ptr<webkit_blob::FileStreamReader>
284 FileSystemBackend::CreateFileStreamReader(
285     const fileapi::FileSystemURL& url,
286     int64 offset,
287     const base::Time& expected_modification_time,
288     fileapi::FileSystemContext* context) const {
289   DCHECK(url.is_valid());
290
291   if (!IsAccessAllowed(url))
292     return scoped_ptr<webkit_blob::FileStreamReader>();
293
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);
309     default:
310       NOTREACHED();
311   }
312   return scoped_ptr<webkit_blob::FileStreamReader>();
313 }
314
315 scoped_ptr<fileapi::FileStreamWriter>
316 FileSystemBackend::CreateFileStreamWriter(
317     const fileapi::FileSystemURL& url,
318     int64 offset,
319     fileapi::FileSystemContext* context) const {
320   DCHECK(url.is_valid());
321
322   if (!IsAccessAllowed(url))
323     return scoped_ptr<fileapi::FileStreamWriter>();
324
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);
341     default:
342       NOTREACHED();
343   }
344   return scoped_ptr<fileapi::FileStreamWriter>();
345 }
346
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);
352 }
353
354 }  // namespace chromeos