1 // Copyright 2014 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/file_system_provider/fileapi/provider_async_file_util.h" 6 7 #include "base/callback.h" 8 #include "base/files/file.h" 9 #include "base/files/file_path.h" 10 #include "base/logging.h" 11 #include "chrome/browser/chromeos/file_system_provider/mount_path_util.h" 12 #include "chrome/browser/chromeos/file_system_provider/provided_file_system_interface.h" 13 #include "content/public/browser/browser_thread.h" 14 #include "storage/browser/fileapi/file_system_operation_context.h" 15 #include "storage/browser/fileapi/file_system_url.h" 16 #include "storage/common/blob/shareable_file_reference.h" 17 18 using content::BrowserThread; 19 20 namespace chromeos { 21 namespace file_system_provider { 22 namespace internal { 23 namespace { 24 25 // Executes GetFileInfo on the UI thread. 26 void GetFileInfoOnUIThread( 27 scoped_ptr<storage::FileSystemOperationContext> context, 28 const storage::FileSystemURL& url, 29 const ProvidedFileSystemInterface::GetMetadataCallback& callback) { 30 util::FileSystemURLParser parser(url); 31 if (!parser.Parse()) { 32 callback.Run(make_scoped_ptr<EntryMetadata>(NULL), 33 base::File::FILE_ERROR_INVALID_OPERATION); 34 return; 35 } 36 37 parser.file_system()->GetMetadata( 38 parser.file_path(), 39 ProvidedFileSystemInterface::METADATA_FIELD_DEFAULT, 40 callback); 41 } 42 43 // Routes the response of GetFileInfo back to the IO thread with a type 44 // conversion. 45 void OnGetFileInfo(const storage::AsyncFileUtil::GetFileInfoCallback& callback, 46 scoped_ptr<EntryMetadata> metadata, 47 base::File::Error result) { 48 if (result != base::File::FILE_OK) { 49 BrowserThread::PostTask(BrowserThread::IO, 50 FROM_HERE, 51 base::Bind(callback, result, base::File::Info())); 52 return; 53 } 54 55 DCHECK(metadata.get()); 56 base::File::Info file_info; 57 58 // TODO(mtomasz): Add support for last modified time and creation time. 59 // See: crbug.com/388540. 60 file_info.size = metadata->size; 61 file_info.is_directory = metadata->is_directory; 62 file_info.is_symbolic_link = false; // Not supported. 63 file_info.last_modified = metadata->modification_time; 64 file_info.last_accessed = metadata->modification_time; // Not supported. 65 file_info.creation_time = metadata->modification_time; // Not supported. 66 67 BrowserThread::PostTask(BrowserThread::IO, 68 FROM_HERE, 69 base::Bind(callback, base::File::FILE_OK, file_info)); 70 } 71 72 // Executes ReadDirectory on the UI thread. 73 void ReadDirectoryOnUIThread( 74 scoped_ptr<storage::FileSystemOperationContext> context, 75 const storage::FileSystemURL& url, 76 const storage::AsyncFileUtil::ReadDirectoryCallback& callback) { 77 util::FileSystemURLParser parser(url); 78 if (!parser.Parse()) { 79 callback.Run(base::File::FILE_ERROR_INVALID_OPERATION, 80 storage::AsyncFileUtil::EntryList(), 81 false /* has_more */); 82 return; 83 } 84 85 parser.file_system()->ReadDirectory(parser.file_path(), callback); 86 } 87 88 // Routes the response of ReadDirectory back to the IO thread. 89 void OnReadDirectory( 90 const storage::AsyncFileUtil::ReadDirectoryCallback& callback, 91 base::File::Error result, 92 const storage::AsyncFileUtil::EntryList& entry_list, 93 bool has_more) { 94 BrowserThread::PostTask(BrowserThread::IO, 95 FROM_HERE, 96 base::Bind(callback, result, entry_list, has_more)); 97 } 98 99 // Executes CreateDirectory on the UI thread. 100 void CreateDirectoryOnUIThread( 101 scoped_ptr<storage::FileSystemOperationContext> context, 102 const storage::FileSystemURL& url, 103 bool exclusive, 104 bool recursive, 105 const storage::AsyncFileUtil::StatusCallback& callback) { 106 util::FileSystemURLParser parser(url); 107 if (!parser.Parse()) { 108 callback.Run(base::File::FILE_ERROR_INVALID_OPERATION); 109 return; 110 } 111 112 parser.file_system()->CreateDirectory( 113 parser.file_path(), recursive, callback); 114 } 115 116 // Routes the response of CreateDirectory back to the IO thread. 117 void OnCreateDirectory(bool exclusive, 118 const storage::AsyncFileUtil::StatusCallback& callback, 119 base::File::Error result) { 120 // If the directory already existed and the operation wasn't exclusive, then 121 // return success anyway, since it is not an error. 122 const base::File::Error error = 123 (result == base::File::FILE_ERROR_EXISTS && !exclusive) 124 ? base::File::FILE_OK 125 : result; 126 127 BrowserThread::PostTask( 128 BrowserThread::IO, FROM_HERE, base::Bind(callback, error)); 129 } 130 131 // Executes DeleteEntry on the UI thread. 132 void DeleteEntryOnUIThread( 133 scoped_ptr<storage::FileSystemOperationContext> context, 134 const storage::FileSystemURL& url, 135 bool recursive, 136 const storage::AsyncFileUtil::StatusCallback& callback) { 137 util::FileSystemURLParser parser(url); 138 if (!parser.Parse()) { 139 callback.Run(base::File::FILE_ERROR_INVALID_OPERATION); 140 return; 141 } 142 143 parser.file_system()->DeleteEntry(parser.file_path(), recursive, callback); 144 } 145 146 // Routes the response of DeleteEntry back to the IO thread. 147 void OnDeleteEntry(const storage::AsyncFileUtil::StatusCallback& callback, 148 base::File::Error result) { 149 BrowserThread::PostTask( 150 BrowserThread::IO, FROM_HERE, base::Bind(callback, result)); 151 } 152 153 // Executes CreateFile on the UI thread. 154 void CreateFileOnUIThread( 155 scoped_ptr<storage::FileSystemOperationContext> context, 156 const storage::FileSystemURL& url, 157 const storage::AsyncFileUtil::StatusCallback& callback) { 158 util::FileSystemURLParser parser(url); 159 if (!parser.Parse()) { 160 callback.Run(base::File::FILE_ERROR_INVALID_OPERATION); 161 return; 162 } 163 164 parser.file_system()->CreateFile(parser.file_path(), callback); 165 } 166 167 // Routes the response of CreateFile to a callback of EnsureFileExists() on the 168 // IO thread. 169 void OnCreateFileForEnsureFileExists( 170 const storage::AsyncFileUtil::EnsureFileExistsCallback& callback, 171 base::File::Error result) { 172 const bool created = result == base::File::FILE_OK; 173 174 // If the file already existed, then return success anyway, since it is not 175 // an error. 176 const base::File::Error error = 177 result == base::File::FILE_ERROR_EXISTS ? base::File::FILE_OK : result; 178 179 BrowserThread::PostTask( 180 BrowserThread::IO, FROM_HERE, base::Bind(callback, error, created)); 181 } 182 183 // Executes CopyEntry on the UI thread. 184 void CopyEntryOnUIThread( 185 scoped_ptr<storage::FileSystemOperationContext> context, 186 const storage::FileSystemURL& source_url, 187 const storage::FileSystemURL& target_url, 188 const storage::AsyncFileUtil::StatusCallback& callback) { 189 util::FileSystemURLParser source_parser(source_url); 190 util::FileSystemURLParser target_parser(target_url); 191 192 if (!source_parser.Parse() || !target_parser.Parse() || 193 source_parser.file_system() != target_parser.file_system()) { 194 callback.Run(base::File::FILE_ERROR_INVALID_OPERATION); 195 return; 196 } 197 198 target_parser.file_system()->CopyEntry( 199 source_parser.file_path(), target_parser.file_path(), callback); 200 } 201 202 // Routes the response of CopyEntry to a callback of CopyLocalFile() on the 203 // IO thread. 204 void OnCopyEntry(const storage::AsyncFileUtil::StatusCallback& callback, 205 base::File::Error result) { 206 BrowserThread::PostTask( 207 BrowserThread::IO, FROM_HERE, base::Bind(callback, result)); 208 } 209 210 // Executes MoveEntry on the UI thread. 211 void MoveEntryOnUIThread( 212 scoped_ptr<storage::FileSystemOperationContext> context, 213 const storage::FileSystemURL& source_url, 214 const storage::FileSystemURL& target_url, 215 const storage::AsyncFileUtil::StatusCallback& callback) { 216 util::FileSystemURLParser source_parser(source_url); 217 util::FileSystemURLParser target_parser(target_url); 218 219 if (!source_parser.Parse() || !target_parser.Parse() || 220 source_parser.file_system() != target_parser.file_system()) { 221 callback.Run(base::File::FILE_ERROR_INVALID_OPERATION); 222 return; 223 } 224 225 target_parser.file_system()->MoveEntry( 226 source_parser.file_path(), target_parser.file_path(), callback); 227 } 228 229 // Routes the response of CopyEntry to a callback of MoveLocalFile() on the 230 // IO thread. 231 void OnMoveEntry(const storage::AsyncFileUtil::StatusCallback& callback, 232 base::File::Error result) { 233 BrowserThread::PostTask( 234 BrowserThread::IO, FROM_HERE, base::Bind(callback, result)); 235 } 236 237 // Executes Truncate on the UI thread. 238 void TruncateOnUIThread( 239 scoped_ptr<storage::FileSystemOperationContext> context, 240 const storage::FileSystemURL& url, 241 int64 length, 242 const storage::AsyncFileUtil::StatusCallback& callback) { 243 util::FileSystemURLParser parser(url); 244 if (!parser.Parse()) { 245 callback.Run(base::File::FILE_ERROR_INVALID_OPERATION); 246 return; 247 } 248 249 parser.file_system()->Truncate(parser.file_path(), length, callback); 250 } 251 252 // Routes the response of Truncate back to the IO thread. 253 void OnTruncate(const storage::AsyncFileUtil::StatusCallback& callback, 254 base::File::Error result) { 255 BrowserThread::PostTask( 256 BrowserThread::IO, FROM_HERE, base::Bind(callback, result)); 257 } 258 259 } // namespace 260 261 ProviderAsyncFileUtil::ProviderAsyncFileUtil() {} 262 263 ProviderAsyncFileUtil::~ProviderAsyncFileUtil() {} 264 265 void ProviderAsyncFileUtil::CreateOrOpen( 266 scoped_ptr<storage::FileSystemOperationContext> context, 267 const storage::FileSystemURL& url, 268 int file_flags, 269 const CreateOrOpenCallback& callback) { 270 DCHECK_CURRENTLY_ON(BrowserThread::IO); 271 if ((file_flags & base::File::FLAG_CREATE) || 272 (file_flags & base::File::FLAG_OPEN_ALWAYS) || 273 (file_flags & base::File::FLAG_CREATE_ALWAYS) || 274 (file_flags & base::File::FLAG_OPEN_TRUNCATED)) { 275 callback.Run(base::File(base::File::FILE_ERROR_ACCESS_DENIED), 276 base::Closure()); 277 return; 278 } 279 280 NOTIMPLEMENTED(); 281 callback.Run(base::File(base::File::FILE_ERROR_INVALID_OPERATION), 282 base::Closure()); 283 } 284 285 void ProviderAsyncFileUtil::EnsureFileExists( 286 scoped_ptr<storage::FileSystemOperationContext> context, 287 const storage::FileSystemURL& url, 288 const EnsureFileExistsCallback& callback) { 289 DCHECK_CURRENTLY_ON(BrowserThread::IO); 290 BrowserThread::PostTask( 291 BrowserThread::UI, 292 FROM_HERE, 293 base::Bind(&CreateFileOnUIThread, 294 base::Passed(&context), 295 url, 296 base::Bind(&OnCreateFileForEnsureFileExists, callback))); 297 } 298 299 void ProviderAsyncFileUtil::CreateDirectory( 300 scoped_ptr<storage::FileSystemOperationContext> context, 301 const storage::FileSystemURL& url, 302 bool exclusive, 303 bool recursive, 304 const StatusCallback& callback) { 305 DCHECK_CURRENTLY_ON(BrowserThread::IO); 306 BrowserThread::PostTask( 307 BrowserThread::UI, 308 FROM_HERE, 309 base::Bind(&CreateDirectoryOnUIThread, 310 base::Passed(&context), 311 url, 312 exclusive, 313 recursive, 314 base::Bind(&OnCreateDirectory, exclusive, callback))); 315 } 316 317 void ProviderAsyncFileUtil::GetFileInfo( 318 scoped_ptr<storage::FileSystemOperationContext> context, 319 const storage::FileSystemURL& url, 320 const GetFileInfoCallback& callback) { 321 DCHECK_CURRENTLY_ON(BrowserThread::IO); 322 BrowserThread::PostTask(BrowserThread::UI, 323 FROM_HERE, 324 base::Bind(&GetFileInfoOnUIThread, 325 base::Passed(&context), 326 url, 327 base::Bind(&OnGetFileInfo, callback))); 328 } 329 330 void ProviderAsyncFileUtil::ReadDirectory( 331 scoped_ptr<storage::FileSystemOperationContext> context, 332 const storage::FileSystemURL& url, 333 const ReadDirectoryCallback& callback) { 334 DCHECK_CURRENTLY_ON(BrowserThread::IO); 335 BrowserThread::PostTask(BrowserThread::UI, 336 FROM_HERE, 337 base::Bind(&ReadDirectoryOnUIThread, 338 base::Passed(&context), 339 url, 340 base::Bind(&OnReadDirectory, callback))); 341 } 342 343 void ProviderAsyncFileUtil::Touch( 344 scoped_ptr<storage::FileSystemOperationContext> context, 345 const storage::FileSystemURL& url, 346 const base::Time& last_access_time, 347 const base::Time& last_modified_time, 348 const StatusCallback& callback) { 349 DCHECK_CURRENTLY_ON(BrowserThread::IO); 350 callback.Run(base::File::FILE_ERROR_ACCESS_DENIED); 351 } 352 353 void ProviderAsyncFileUtil::Truncate( 354 scoped_ptr<storage::FileSystemOperationContext> context, 355 const storage::FileSystemURL& url, 356 int64 length, 357 const StatusCallback& callback) { 358 DCHECK_CURRENTLY_ON(BrowserThread::IO); 359 BrowserThread::PostTask(BrowserThread::UI, 360 FROM_HERE, 361 base::Bind(&TruncateOnUIThread, 362 base::Passed(&context), 363 url, 364 length, 365 base::Bind(&OnTruncate, callback))); 366 } 367 368 void ProviderAsyncFileUtil::CopyFileLocal( 369 scoped_ptr<storage::FileSystemOperationContext> context, 370 const storage::FileSystemURL& src_url, 371 const storage::FileSystemURL& dest_url, 372 CopyOrMoveOption option, 373 const CopyFileProgressCallback& progress_callback, 374 const StatusCallback& callback) { 375 DCHECK_CURRENTLY_ON(BrowserThread::IO); 376 // TODO(mtomasz): Consier adding support for options (preserving last modified 377 // time) as well as the progress callback. 378 BrowserThread::PostTask(BrowserThread::UI, 379 FROM_HERE, 380 base::Bind(&CopyEntryOnUIThread, 381 base::Passed(&context), 382 src_url, 383 dest_url, 384 base::Bind(&OnCopyEntry, callback))); 385 } 386 387 void ProviderAsyncFileUtil::MoveFileLocal( 388 scoped_ptr<storage::FileSystemOperationContext> context, 389 const storage::FileSystemURL& src_url, 390 const storage::FileSystemURL& dest_url, 391 CopyOrMoveOption option, 392 const StatusCallback& callback) { 393 DCHECK_CURRENTLY_ON(BrowserThread::IO); 394 // TODO(mtomasz): Consier adding support for options (preserving last modified 395 // time) as well as the progress callback. 396 BrowserThread::PostTask(BrowserThread::UI, 397 FROM_HERE, 398 base::Bind(&MoveEntryOnUIThread, 399 base::Passed(&context), 400 src_url, 401 dest_url, 402 base::Bind(&OnMoveEntry, callback))); 403 } 404 405 void ProviderAsyncFileUtil::CopyInForeignFile( 406 scoped_ptr<storage::FileSystemOperationContext> context, 407 const base::FilePath& src_file_path, 408 const storage::FileSystemURL& dest_url, 409 const StatusCallback& callback) { 410 DCHECK_CURRENTLY_ON(BrowserThread::IO); 411 callback.Run(base::File::FILE_ERROR_ACCESS_DENIED); 412 } 413 414 void ProviderAsyncFileUtil::DeleteFile( 415 scoped_ptr<storage::FileSystemOperationContext> context, 416 const storage::FileSystemURL& url, 417 const StatusCallback& callback) { 418 DCHECK_CURRENTLY_ON(BrowserThread::IO); 419 BrowserThread::PostTask(BrowserThread::UI, 420 FROM_HERE, 421 base::Bind(&DeleteEntryOnUIThread, 422 base::Passed(&context), 423 url, 424 false, // recursive 425 base::Bind(&OnDeleteEntry, callback))); 426 } 427 428 void ProviderAsyncFileUtil::DeleteDirectory( 429 scoped_ptr<storage::FileSystemOperationContext> context, 430 const storage::FileSystemURL& url, 431 const StatusCallback& callback) { 432 DCHECK_CURRENTLY_ON(BrowserThread::IO); 433 BrowserThread::PostTask(BrowserThread::UI, 434 FROM_HERE, 435 base::Bind(&DeleteEntryOnUIThread, 436 base::Passed(&context), 437 url, 438 false, // recursive 439 base::Bind(&OnDeleteEntry, callback))); 440 } 441 442 void ProviderAsyncFileUtil::DeleteRecursively( 443 scoped_ptr<storage::FileSystemOperationContext> context, 444 const storage::FileSystemURL& url, 445 const StatusCallback& callback) { 446 DCHECK_CURRENTLY_ON(BrowserThread::IO); 447 BrowserThread::PostTask(BrowserThread::UI, 448 FROM_HERE, 449 base::Bind(&DeleteEntryOnUIThread, 450 base::Passed(&context), 451 url, 452 true, // recursive 453 base::Bind(&OnDeleteEntry, callback))); 454 } 455 456 void ProviderAsyncFileUtil::CreateSnapshotFile( 457 scoped_ptr<storage::FileSystemOperationContext> context, 458 const storage::FileSystemURL& url, 459 const CreateSnapshotFileCallback& callback) { 460 DCHECK_CURRENTLY_ON(BrowserThread::IO); 461 NOTIMPLEMENTED(); 462 callback.Run(base::File::FILE_ERROR_INVALID_OPERATION, 463 base::File::Info(), 464 base::FilePath(), 465 scoped_refptr<storage::ShareableFileReference>()); 466 } 467 468 } // namespace internal 469 } // namespace file_system_provider 470 } // namespace chromeos 471