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 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 142 fileapi::FileSystemQuotaUtil* FileSystemBackend::GetQuotaUtil() { 143 // No quota support. 144 return NULL; 145 } 146 147 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 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 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 210 void FileSystemBackend::RevokeAccessForExtension( 211 const std::string& extension_id) { 212 file_access_permissions_->RevokePermissions(extension_id); 213 } 214 215 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 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* 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 252 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 280 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> 288 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> 320 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 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