• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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