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