file_system_backend.cc revision 68043e1e95eeb07d5cae7aca370b26518b0867d6
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/message_loop/message_loop.h" 10#include "base/path_service.h" 11#include "base/strings/stringprintf.h" 12#include "base/strings/utf_string_conversions.h" 13#include "base/synchronization/lock.h" 14#include "chrome/browser/chromeos/fileapi/file_access_permissions.h" 15#include "chrome/browser/chromeos/fileapi/file_system_backend_delegate.h" 16#include "chromeos/dbus/cros_disks_client.h" 17#include "webkit/browser/blob/file_stream_reader.h" 18#include "webkit/browser/fileapi/async_file_util.h" 19#include "webkit/browser/fileapi/external_mount_points.h" 20#include "webkit/browser/fileapi/file_stream_writer.h" 21#include "webkit/browser/fileapi/file_system_context.h" 22#include "webkit/browser/fileapi/file_system_operation.h" 23#include "webkit/browser/fileapi/file_system_operation_context.h" 24#include "webkit/browser/fileapi/file_system_url.h" 25#include "webkit/browser/fileapi/isolated_context.h" 26 27namespace { 28 29const char kChromeUIScheme[] = "chrome"; 30 31} // namespace 32 33namespace chromeos { 34 35// static 36bool FileSystemBackend::CanHandleURL(const fileapi::FileSystemURL& url) { 37 if (!url.is_valid()) 38 return false; 39 return url.type() == fileapi::kFileSystemTypeNativeLocal || 40 url.type() == fileapi::kFileSystemTypeRestrictedNativeLocal || 41 url.type() == fileapi::kFileSystemTypeDrive; 42} 43 44FileSystemBackend::FileSystemBackend( 45 FileSystemBackendDelegate* drive_delegate, 46 scoped_refptr<quota::SpecialStoragePolicy> special_storage_policy, 47 scoped_refptr<fileapi::ExternalMountPoints> mount_points, 48 fileapi::ExternalMountPoints* system_mount_points) 49 : special_storage_policy_(special_storage_policy), 50 file_access_permissions_(new FileAccessPermissions()), 51 local_file_util_(fileapi::AsyncFileUtil::CreateForLocalFileSystem()), 52 drive_delegate_(drive_delegate), 53 mount_points_(mount_points), 54 system_mount_points_(system_mount_points) { 55} 56 57FileSystemBackend::~FileSystemBackend() { 58} 59 60void FileSystemBackend::AddSystemMountPoints() { 61 // RegisterFileSystem() is no-op if the mount point with the same name 62 // already exists, hence it's safe to call without checking if a mount 63 // point already exists or not. 64 65 // TODO(satorux): "Downloads" directory should probably be per-profile. For 66 // this to be per-profile, a unique directory path should be chosen per 67 // profile, and the mount point should be added to 68 // mount_points_. crbug.com/247236 69 base::FilePath home_path; 70 if (PathService::Get(base::DIR_HOME, &home_path)) { 71 system_mount_points_->RegisterFileSystem( 72 "Downloads", 73 fileapi::kFileSystemTypeNativeLocal, 74 home_path.AppendASCII("Downloads")); 75 } 76 77 system_mount_points_->RegisterFileSystem( 78 "archive", 79 fileapi::kFileSystemTypeNativeLocal, 80 chromeos::CrosDisksClient::GetArchiveMountPoint()); 81 system_mount_points_->RegisterFileSystem( 82 "removable", 83 fileapi::kFileSystemTypeNativeLocal, 84 chromeos::CrosDisksClient::GetRemovableDiskMountPoint()); 85 system_mount_points_->RegisterFileSystem( 86 "oem", 87 fileapi::kFileSystemTypeRestrictedNativeLocal, 88 base::FilePath(FILE_PATH_LITERAL("/usr/share/oem"))); 89} 90 91bool FileSystemBackend::CanHandleType(fileapi::FileSystemType type) const { 92 switch (type) { 93 case fileapi::kFileSystemTypeExternal: 94 case fileapi::kFileSystemTypeDrive: 95 case fileapi::kFileSystemTypeRestrictedNativeLocal: 96 case fileapi::kFileSystemTypeNativeLocal: 97 case fileapi::kFileSystemTypeNativeForPlatformApp: 98 return true; 99 default: 100 return false; 101 } 102} 103 104void FileSystemBackend::Initialize(fileapi::FileSystemContext* context) { 105} 106 107void FileSystemBackend::OpenFileSystem( 108 const GURL& origin_url, 109 fileapi::FileSystemType type, 110 fileapi::OpenFileSystemMode mode, 111 const OpenFileSystemCallback& callback) { 112 DCHECK(CanHandleType(type)); 113 // TODO(nhiroki): Avoid this hard-coded mount type to support multiple 114 // filesystems (http://crbug.com/297412). 115 fileapi::FileSystemType mount_type = fileapi::kFileSystemTypeExternal; 116 // Nothing to validate for external filesystem. 117 callback.Run(GetFileSystemRootURI(origin_url, mount_type), 118 GetFileSystemName(origin_url, mount_type), 119 base::PLATFORM_FILE_OK); 120} 121 122fileapi::FileSystemQuotaUtil* FileSystemBackend::GetQuotaUtil() { 123 // No quota support. 124 return NULL; 125} 126 127bool FileSystemBackend::IsAccessAllowed( 128 const fileapi::FileSystemURL& url) const { 129 if (!url.is_valid()) 130 return false; 131 132 // Permit access to mount points from internal WebUI. 133 const GURL& origin_url = url.origin(); 134 if (origin_url.SchemeIs(kChromeUIScheme)) 135 return true; 136 137 // No extra check is needed for isolated file systems. 138 if (url.mount_type() == fileapi::kFileSystemTypeIsolated) 139 return true; 140 141 if (!CanHandleURL(url)) 142 return false; 143 144 std::string extension_id = origin_url.host(); 145 // TODO(mtomasz): Temporarily whitelist TimeScapes. Remove this in M-31. 146 // See: crbug.com/271946 147 if (extension_id == "mlbmkoenclnokonejhlfakkeabdlmpek" && 148 url.type() == fileapi::kFileSystemTypeRestrictedNativeLocal) { 149 return true; 150 } 151 152 // Check first to make sure this extension has fileBrowserHander permissions. 153 if (!special_storage_policy_->IsFileHandler(extension_id)) 154 return false; 155 156 return file_access_permissions_->HasAccessPermission(extension_id, 157 url.virtual_path()); 158} 159 160void FileSystemBackend::GrantFullAccessToExtension( 161 const std::string& extension_id) { 162 DCHECK(special_storage_policy_->IsFileHandler(extension_id)); 163 if (!special_storage_policy_->IsFileHandler(extension_id)) 164 return; 165 166 std::vector<fileapi::MountPoints::MountPointInfo> files; 167 mount_points_->AddMountPointInfosTo(&files); 168 system_mount_points_->AddMountPointInfosTo(&files); 169 170 for (size_t i = 0; i < files.size(); ++i) { 171 file_access_permissions_->GrantAccessPermission( 172 extension_id, 173 base::FilePath::FromUTF8Unsafe(files[i].name)); 174 } 175} 176 177void FileSystemBackend::GrantFileAccessToExtension( 178 const std::string& extension_id, const base::FilePath& virtual_path) { 179 // All we care about here is access from extensions for now. 180 DCHECK(special_storage_policy_->IsFileHandler(extension_id)); 181 if (!special_storage_policy_->IsFileHandler(extension_id)) 182 return; 183 184 std::string id; 185 fileapi::FileSystemType type; 186 base::FilePath path; 187 if (!mount_points_->CrackVirtualPath(virtual_path, &id, &type, &path) && 188 !system_mount_points_->CrackVirtualPath(virtual_path, 189 &id, &type, &path)) { 190 return; 191 } 192 193 if (type == fileapi::kFileSystemTypeRestrictedNativeLocal) { 194 LOG(ERROR) << "Can't grant access for restricted mount point"; 195 return; 196 } 197 198 file_access_permissions_->GrantAccessPermission(extension_id, virtual_path); 199} 200 201void FileSystemBackend::RevokeAccessForExtension( 202 const std::string& extension_id) { 203 file_access_permissions_->RevokePermissions(extension_id); 204} 205 206std::vector<base::FilePath> FileSystemBackend::GetRootDirectories() const { 207 std::vector<fileapi::MountPoints::MountPointInfo> mount_points; 208 mount_points_->AddMountPointInfosTo(&mount_points); 209 system_mount_points_->AddMountPointInfosTo(&mount_points); 210 211 std::vector<base::FilePath> root_dirs; 212 for (size_t i = 0; i < mount_points.size(); ++i) 213 root_dirs.push_back(mount_points[i].path); 214 return root_dirs; 215} 216 217fileapi::AsyncFileUtil* FileSystemBackend::GetAsyncFileUtil( 218 fileapi::FileSystemType type) { 219 if (type == fileapi::kFileSystemTypeDrive) 220 return drive_delegate_->GetAsyncFileUtil(type); 221 222 DCHECK(type == fileapi::kFileSystemTypeNativeLocal || 223 type == fileapi::kFileSystemTypeRestrictedNativeLocal); 224 return local_file_util_.get(); 225} 226 227fileapi::CopyOrMoveFileValidatorFactory* 228FileSystemBackend::GetCopyOrMoveFileValidatorFactory( 229 fileapi::FileSystemType type, base::PlatformFileError* error_code) { 230 DCHECK(error_code); 231 *error_code = base::PLATFORM_FILE_OK; 232 return NULL; 233} 234 235fileapi::FileSystemOperation* FileSystemBackend::CreateFileSystemOperation( 236 const fileapi::FileSystemURL& url, 237 fileapi::FileSystemContext* context, 238 base::PlatformFileError* error_code) const { 239 DCHECK(url.is_valid()); 240 241 if (!IsAccessAllowed(url)) { 242 *error_code = base::PLATFORM_FILE_ERROR_SECURITY; 243 return NULL; 244 } 245 246 DCHECK(url.type() == fileapi::kFileSystemTypeNativeLocal || 247 url.type() == fileapi::kFileSystemTypeRestrictedNativeLocal || 248 url.type() == fileapi::kFileSystemTypeDrive); 249 return fileapi::FileSystemOperation::Create( 250 url, context, 251 make_scoped_ptr(new fileapi::FileSystemOperationContext(context))); 252} 253 254scoped_ptr<webkit_blob::FileStreamReader> 255FileSystemBackend::CreateFileStreamReader( 256 const fileapi::FileSystemURL& url, 257 int64 offset, 258 const base::Time& expected_modification_time, 259 fileapi::FileSystemContext* context) const { 260 DCHECK(url.is_valid()); 261 262 if (!IsAccessAllowed(url)) 263 return scoped_ptr<webkit_blob::FileStreamReader>(); 264 265 if (url.type() == fileapi::kFileSystemTypeDrive) { 266 return drive_delegate_->CreateFileStreamReader( 267 url, offset, expected_modification_time, context); 268 } 269 270 return scoped_ptr<webkit_blob::FileStreamReader>( 271 webkit_blob::FileStreamReader::CreateForFileSystemFile( 272 context, url, offset, expected_modification_time)); 273} 274 275scoped_ptr<fileapi::FileStreamWriter> 276FileSystemBackend::CreateFileStreamWriter( 277 const fileapi::FileSystemURL& url, 278 int64 offset, 279 fileapi::FileSystemContext* context) const { 280 DCHECK(url.is_valid()); 281 282 if (!IsAccessAllowed(url)) 283 return scoped_ptr<fileapi::FileStreamWriter>(); 284 285 if (url.type() == fileapi::kFileSystemTypeDrive) 286 return drive_delegate_->CreateFileStreamWriter(url, offset, context); 287 288 if (url.type() == fileapi::kFileSystemTypeRestrictedNativeLocal) 289 return scoped_ptr<fileapi::FileStreamWriter>(); 290 291 DCHECK(url.type() == fileapi::kFileSystemTypeNativeLocal); 292 return scoped_ptr<fileapi::FileStreamWriter>( 293 fileapi::FileStreamWriter::CreateForLocalFile( 294 context->default_file_task_runner(), url.path(), offset)); 295} 296 297bool FileSystemBackend::GetVirtualPath( 298 const base::FilePath& filesystem_path, 299 base::FilePath* virtual_path) { 300 return mount_points_->GetVirtualPath(filesystem_path, virtual_path) || 301 system_mount_points_->GetVirtualPath(filesystem_path, virtual_path); 302} 303 304} // namespace chromeos 305