file_system_backend.cc revision 5f1c94371a64b3196d4be9466099bb892df9b88e
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 23namespace chromeos { 24 25// static 26bool 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 36FileSystemBackend::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 52FileSystemBackend::~FileSystemBackend() { 53} 54 55void 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 76bool 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 91void FileSystemBackend::Initialize(fileapi::FileSystemContext* context) { 92} 93 94void 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 142fileapi::FileSystemQuotaUtil* FileSystemBackend::GetQuotaUtil() { 143 // No quota support. 144 return NULL; 145} 146 147bool 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_ || 169 !special_storage_policy_->IsFileHandler(extension_id)) 170 return false; 171 172 return file_access_permissions_->HasAccessPermission(extension_id, 173 url.virtual_path()); 174} 175 176void FileSystemBackend::GrantFullAccessToExtension( 177 const std::string& extension_id) { 178 if (!special_storage_policy_) 179 return; 180 if (!special_storage_policy_->IsFileHandler(extension_id)) { 181 NOTREACHED(); 182 return; 183 } 184 file_access_permissions_->GrantFullAccessPermission(extension_id); 185} 186 187void FileSystemBackend::GrantFileAccessToExtension( 188 const std::string& extension_id, const base::FilePath& virtual_path) { 189 if (!special_storage_policy_) 190 return; 191 // All we care about here is access from extensions for now. 192 if (!special_storage_policy_->IsFileHandler(extension_id)) { 193 NOTREACHED(); 194 return; 195 } 196 197 std::string id; 198 fileapi::FileSystemType type; 199 std::string cracked_id; 200 base::FilePath path; 201 fileapi::FileSystemMountOption option; 202 if (!mount_points_->CrackVirtualPath(virtual_path, &id, &type, &cracked_id, 203 &path, &option) && 204 !system_mount_points_->CrackVirtualPath(virtual_path, &id, &type, 205 &cracked_id, &path, &option)) { 206 return; 207 } 208 209 if (type == fileapi::kFileSystemTypeRestrictedNativeLocal) { 210 LOG(ERROR) << "Can't grant access for restricted mount point"; 211 return; 212 } 213 214 file_access_permissions_->GrantAccessPermission(extension_id, virtual_path); 215} 216 217void FileSystemBackend::RevokeAccessForExtension( 218 const std::string& extension_id) { 219 file_access_permissions_->RevokePermissions(extension_id); 220} 221 222std::vector<base::FilePath> FileSystemBackend::GetRootDirectories() const { 223 std::vector<fileapi::MountPoints::MountPointInfo> mount_points; 224 mount_points_->AddMountPointInfosTo(&mount_points); 225 system_mount_points_->AddMountPointInfosTo(&mount_points); 226 227 std::vector<base::FilePath> root_dirs; 228 for (size_t i = 0; i < mount_points.size(); ++i) 229 root_dirs.push_back(mount_points[i].path); 230 return root_dirs; 231} 232 233fileapi::AsyncFileUtil* FileSystemBackend::GetAsyncFileUtil( 234 fileapi::FileSystemType type) { 235 switch (type) { 236 case fileapi::kFileSystemTypeDrive: 237 return drive_delegate_->GetAsyncFileUtil(type); 238 case fileapi::kFileSystemTypeProvided: 239 return file_system_provider_delegate_->GetAsyncFileUtil(type); 240 case fileapi::kFileSystemTypeNativeLocal: 241 case fileapi::kFileSystemTypeRestrictedNativeLocal: 242 return local_file_util_.get(); 243 case fileapi::kFileSystemTypeDeviceMediaAsFileStorage: 244 return mtp_delegate_->GetAsyncFileUtil(type); 245 default: 246 NOTREACHED(); 247 } 248 return NULL; 249} 250 251fileapi::CopyOrMoveFileValidatorFactory* 252FileSystemBackend::GetCopyOrMoveFileValidatorFactory( 253 fileapi::FileSystemType type, base::File::Error* error_code) { 254 DCHECK(error_code); 255 *error_code = base::File::FILE_OK; 256 return NULL; 257} 258 259fileapi::FileSystemOperation* FileSystemBackend::CreateFileSystemOperation( 260 const fileapi::FileSystemURL& url, 261 fileapi::FileSystemContext* context, 262 base::File::Error* error_code) const { 263 DCHECK(url.is_valid()); 264 265 if (!IsAccessAllowed(url)) { 266 *error_code = base::File::FILE_ERROR_SECURITY; 267 return NULL; 268 } 269 270 if (url.type() == fileapi::kFileSystemTypeDeviceMediaAsFileStorage) { 271 // MTP file operations run on MediaTaskRunner. 272 return fileapi::FileSystemOperation::Create( 273 url, context, 274 make_scoped_ptr(new fileapi::FileSystemOperationContext( 275 context, MediaFileSystemBackend::MediaTaskRunner()))); 276 } 277 278 DCHECK(url.type() == fileapi::kFileSystemTypeNativeLocal || 279 url.type() == fileapi::kFileSystemTypeRestrictedNativeLocal || 280 url.type() == fileapi::kFileSystemTypeDrive || 281 url.type() == fileapi::kFileSystemTypeProvided); 282 return fileapi::FileSystemOperation::Create( 283 url, context, 284 make_scoped_ptr(new fileapi::FileSystemOperationContext(context))); 285} 286 287bool FileSystemBackend::SupportsStreaming( 288 const fileapi::FileSystemURL& url) const { 289 return url.type() == fileapi::kFileSystemTypeDrive || 290 url.type() == fileapi::kFileSystemTypeProvided || 291 url.type() == fileapi::kFileSystemTypeDeviceMediaAsFileStorage; 292} 293 294scoped_ptr<webkit_blob::FileStreamReader> 295FileSystemBackend::CreateFileStreamReader( 296 const fileapi::FileSystemURL& url, 297 int64 offset, 298 const base::Time& expected_modification_time, 299 fileapi::FileSystemContext* context) const { 300 DCHECK(url.is_valid()); 301 302 if (!IsAccessAllowed(url)) 303 return scoped_ptr<webkit_blob::FileStreamReader>(); 304 305 switch (url.type()) { 306 case fileapi::kFileSystemTypeDrive: 307 return drive_delegate_->CreateFileStreamReader( 308 url, offset, expected_modification_time, context); 309 case fileapi::kFileSystemTypeProvided: 310 return file_system_provider_delegate_->CreateFileStreamReader( 311 url, offset, expected_modification_time, context); 312 case fileapi::kFileSystemTypeNativeLocal: 313 case fileapi::kFileSystemTypeRestrictedNativeLocal: 314 return scoped_ptr<webkit_blob::FileStreamReader>( 315 webkit_blob::FileStreamReader::CreateForFileSystemFile( 316 context, url, offset, expected_modification_time)); 317 case fileapi::kFileSystemTypeDeviceMediaAsFileStorage: 318 return mtp_delegate_->CreateFileStreamReader( 319 url, offset, expected_modification_time, context); 320 default: 321 NOTREACHED(); 322 } 323 return scoped_ptr<webkit_blob::FileStreamReader>(); 324} 325 326scoped_ptr<fileapi::FileStreamWriter> 327FileSystemBackend::CreateFileStreamWriter( 328 const fileapi::FileSystemURL& url, 329 int64 offset, 330 fileapi::FileSystemContext* context) const { 331 DCHECK(url.is_valid()); 332 333 if (!IsAccessAllowed(url)) 334 return scoped_ptr<fileapi::FileStreamWriter>(); 335 336 switch (url.type()) { 337 case fileapi::kFileSystemTypeDrive: 338 return drive_delegate_->CreateFileStreamWriter(url, offset, context); 339 case fileapi::kFileSystemTypeProvided: 340 return file_system_provider_delegate_->CreateFileStreamWriter( 341 url, offset, context); 342 case fileapi::kFileSystemTypeNativeLocal: 343 return scoped_ptr<fileapi::FileStreamWriter>( 344 fileapi::FileStreamWriter::CreateForLocalFile( 345 context->default_file_task_runner(), url.path(), offset, 346 fileapi::FileStreamWriter::OPEN_EXISTING_FILE)); 347 case fileapi::kFileSystemTypeRestrictedNativeLocal: 348 // Restricted native local file system is read only. 349 return scoped_ptr<fileapi::FileStreamWriter>(); 350 case fileapi::kFileSystemTypeDeviceMediaAsFileStorage: 351 return mtp_delegate_->CreateFileStreamWriter(url, offset, context); 352 default: 353 NOTREACHED(); 354 } 355 return scoped_ptr<fileapi::FileStreamWriter>(); 356} 357 358bool FileSystemBackend::GetVirtualPath( 359 const base::FilePath& filesystem_path, 360 base::FilePath* virtual_path) { 361 return mount_points_->GetVirtualPath(filesystem_path, virtual_path) || 362 system_mount_points_->GetVirtualPath(filesystem_path, virtual_path); 363} 364 365} // namespace chromeos 366