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/extensions/file_manager/private_api_file_system.h" 6 7 #include <sys/statvfs.h> 8 9 #include "base/posix/eintr_wrapper.h" 10 #include "base/strings/string_number_conversions.h" 11 #include "base/strings/stringprintf.h" 12 #include "base/task_runner_util.h" 13 #include "base/threading/sequenced_worker_pool.h" 14 #include "chrome/browser/browser_process.h" 15 #include "chrome/browser/chromeos/drive/drive.pb.h" 16 #include "chrome/browser/chromeos/drive/file_system_interface.h" 17 #include "chrome/browser/chromeos/drive/file_system_util.h" 18 #include "chrome/browser/chromeos/extensions/file_manager/event_router.h" 19 #include "chrome/browser/chromeos/extensions/file_manager/file_browser_private_api.h" 20 #include "chrome/browser/chromeos/extensions/file_manager/private_api_util.h" 21 #include "chrome/browser/chromeos/file_manager/fileapi_util.h" 22 #include "chrome/browser/chromeos/file_manager/volume_manager.h" 23 #include "chrome/browser/chromeos/fileapi/file_system_backend.h" 24 #include "chrome/browser/profiles/profile.h" 25 #include "chrome/browser/profiles/profile_manager.h" 26 #include "chrome/common/extensions/api/file_browser_private.h" 27 #include "chrome/common/extensions/api/file_browser_private_internal.h" 28 #include "chromeos/disks/disk_mount_manager.h" 29 #include "content/public/browser/child_process_security_policy.h" 30 #include "content/public/browser/render_process_host.h" 31 #include "content/public/browser/render_view_host.h" 32 #include "webkit/browser/fileapi/file_system_context.h" 33 #include "webkit/browser/fileapi/file_system_file_util.h" 34 #include "webkit/browser/fileapi/file_system_operation_context.h" 35 #include "webkit/browser/fileapi/file_system_operation_runner.h" 36 #include "webkit/browser/fileapi/file_system_url.h" 37 #include "webkit/common/fileapi/file_system_info.h" 38 #include "webkit/common/fileapi/file_system_types.h" 39 #include "webkit/common/fileapi/file_system_util.h" 40 41 using chromeos::disks::DiskMountManager; 42 using content::BrowserThread; 43 using content::ChildProcessSecurityPolicy; 44 using file_manager::util::EntryDefinition; 45 using file_manager::util::FileDefinition; 46 using fileapi::FileSystemURL; 47 48 namespace extensions { 49 namespace { 50 51 // Retrieves total and remaining available size on |mount_path|. 52 void GetSizeStatsOnBlockingPool(const std::string& mount_path, 53 uint64* total_size, 54 uint64* remaining_size) { 55 struct statvfs stat = {}; // Zero-clear 56 if (HANDLE_EINTR(statvfs(mount_path.c_str(), &stat)) == 0) { 57 *total_size = static_cast<uint64>(stat.f_blocks) * stat.f_frsize; 58 *remaining_size = static_cast<uint64>(stat.f_bavail) * stat.f_frsize; 59 } 60 } 61 62 // Retrieves the maximum file name length of the file system of |path|. 63 // Returns 0 if it could not be queried. 64 size_t GetFileNameMaxLengthOnBlockingPool(const std::string& path) { 65 struct statvfs stat = {}; 66 if (HANDLE_EINTR(statvfs(path.c_str(), &stat)) != 0) { 67 // The filesystem seems not supporting statvfs(). Assume it to be a commonly 68 // used bound 255, and log the failure. 69 LOG(ERROR) << "Cannot statvfs() the name length limit for: " << path; 70 return 255; 71 } 72 return stat.f_namemax; 73 } 74 75 // Returns EventRouter for the |profile_id| if available. 76 file_manager::EventRouter* GetEventRouterByProfileId(void* profile_id) { 77 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 78 79 // |profile_id| needs to be checked with ProfileManager::IsValidProfile 80 // before using it. 81 Profile* profile = reinterpret_cast<Profile*>(profile_id); 82 if (!g_browser_process->profile_manager()->IsValidProfile(profile)) 83 return NULL; 84 85 return file_manager::FileBrowserPrivateAPI::Get(profile)->event_router(); 86 } 87 88 // Notifies the copy progress to extensions via event router. 89 void NotifyCopyProgress( 90 void* profile_id, 91 fileapi::FileSystemOperationRunner::OperationID operation_id, 92 fileapi::FileSystemOperation::CopyProgressType type, 93 const FileSystemURL& source_url, 94 const FileSystemURL& destination_url, 95 int64 size) { 96 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 97 98 file_manager::EventRouter* event_router = 99 GetEventRouterByProfileId(profile_id); 100 if (event_router) { 101 event_router->OnCopyProgress( 102 operation_id, type, 103 source_url.ToGURL(), destination_url.ToGURL(), size); 104 } 105 } 106 107 // Callback invoked periodically on progress update of Copy(). 108 void OnCopyProgress( 109 void* profile_id, 110 fileapi::FileSystemOperationRunner::OperationID* operation_id, 111 fileapi::FileSystemOperation::CopyProgressType type, 112 const FileSystemURL& source_url, 113 const FileSystemURL& destination_url, 114 int64 size) { 115 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 116 117 BrowserThread::PostTask( 118 BrowserThread::UI, FROM_HERE, 119 base::Bind(&NotifyCopyProgress, 120 profile_id, *operation_id, type, 121 source_url, destination_url, size)); 122 } 123 124 // Notifies the copy completion to extensions via event router. 125 void NotifyCopyCompletion( 126 void* profile_id, 127 fileapi::FileSystemOperationRunner::OperationID operation_id, 128 const FileSystemURL& source_url, 129 const FileSystemURL& destination_url, 130 base::File::Error error) { 131 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 132 133 file_manager::EventRouter* event_router = 134 GetEventRouterByProfileId(profile_id); 135 if (event_router) 136 event_router->OnCopyCompleted( 137 operation_id, 138 source_url.ToGURL(), destination_url.ToGURL(), error); 139 } 140 141 // Callback invoked upon completion of Copy() (regardless of succeeded or 142 // failed). 143 void OnCopyCompleted( 144 void* profile_id, 145 fileapi::FileSystemOperationRunner::OperationID* operation_id, 146 const FileSystemURL& source_url, 147 const FileSystemURL& destination_url, 148 base::File::Error error) { 149 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 150 151 BrowserThread::PostTask( 152 BrowserThread::UI, FROM_HERE, 153 base::Bind(&NotifyCopyCompletion, 154 profile_id, *operation_id, 155 source_url, destination_url, error)); 156 } 157 158 // Starts the copy operation via FileSystemOperationRunner. 159 fileapi::FileSystemOperationRunner::OperationID StartCopyOnIOThread( 160 void* profile_id, 161 scoped_refptr<fileapi::FileSystemContext> file_system_context, 162 const FileSystemURL& source_url, 163 const FileSystemURL& destination_url) { 164 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 165 166 // Note: |operation_id| is owned by the callback for 167 // FileSystemOperationRunner::Copy(). It is always called in the next message 168 // loop or later, so at least during this invocation it should alive. 169 fileapi::FileSystemOperationRunner::OperationID* operation_id = 170 new fileapi::FileSystemOperationRunner::OperationID; 171 *operation_id = file_system_context->operation_runner()->Copy( 172 source_url, destination_url, 173 fileapi::FileSystemOperation::OPTION_PRESERVE_LAST_MODIFIED, 174 base::Bind(&OnCopyProgress, 175 profile_id, base::Unretained(operation_id)), 176 base::Bind(&OnCopyCompleted, 177 profile_id, base::Owned(operation_id), 178 source_url, destination_url)); 179 return *operation_id; 180 } 181 182 void OnCopyCancelled(base::File::Error error) { 183 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 184 185 // We just ignore the status if the copy is actually cancelled or not, 186 // because failing cancellation means the operation is not running now. 187 DLOG_IF(WARNING, error != base::File::FILE_OK) 188 << "Failed to cancel copy: " << error; 189 } 190 191 // Cancels the running copy operation identified by |operation_id|. 192 void CancelCopyOnIOThread( 193 scoped_refptr<fileapi::FileSystemContext> file_system_context, 194 fileapi::FileSystemOperationRunner::OperationID operation_id) { 195 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 196 197 file_system_context->operation_runner()->Cancel( 198 operation_id, base::Bind(&OnCopyCancelled)); 199 } 200 201 } // namespace 202 203 void FileBrowserPrivateRequestFileSystemFunction::DidFail( 204 base::File::Error error_code) { 205 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 206 207 SetError(base::StringPrintf("File error %d", static_cast<int>(error_code))); 208 SendResponse(false); 209 } 210 211 bool FileBrowserPrivateRequestFileSystemFunction:: 212 SetupFileSystemAccessPermissions( 213 scoped_refptr<fileapi::FileSystemContext> file_system_context, 214 int child_id, 215 Profile* profile, 216 scoped_refptr<const extensions::Extension> extension) { 217 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 218 219 if (!extension.get()) 220 return false; 221 222 // Make sure that only component extension can access the entire 223 // local file system. 224 if (extension_->location() != extensions::Manifest::COMPONENT) { 225 NOTREACHED() << "Private method access by non-component extension " 226 << extension->id(); 227 return false; 228 } 229 230 fileapi::ExternalFileSystemBackend* backend = 231 file_system_context->external_backend(); 232 if (!backend) 233 return false; 234 235 // Grant full access to File API from this component extension. 236 backend->GrantFullAccessToExtension(extension_->id()); 237 238 // Grant R/W file permissions to the renderer hosting component 239 // extension for all paths exposed by our local file system backend. 240 std::vector<base::FilePath> root_dirs = backend->GetRootDirectories(); 241 for (size_t i = 0; i < root_dirs.size(); ++i) { 242 ChildProcessSecurityPolicy::GetInstance()->GrantCreateReadWriteFile( 243 child_id, root_dirs[i]); 244 } 245 246 // Grant R/W permissions to profile-specific directories (Drive, Downloads) 247 // from other profiles. Those directories may not be mounted at this moment 248 // yet, so we need to do this separately from the above loop over 249 // GetRootDirectories(). 250 const std::vector<Profile*>& profiles = 251 g_browser_process->profile_manager()->GetLoadedProfiles(); 252 for (size_t i = 0; i < profiles.size(); ++i) { 253 if (!profiles[i]->IsOffTheRecord()) { 254 file_manager::util::SetupProfileFileAccessPermissions(child_id, 255 profiles[i]); 256 } 257 } 258 259 return true; 260 } 261 262 bool FileBrowserPrivateRequestFileSystemFunction::RunAsync() { 263 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 264 using extensions::api::file_browser_private::RequestFileSystem::Params; 265 const scoped_ptr<Params> params(Params::Create(*args_)); 266 EXTENSION_FUNCTION_VALIDATE(params); 267 268 if (!dispatcher() || !render_view_host() || !render_view_host()->GetProcess()) 269 return false; 270 271 set_log_on_completion(true); 272 273 using file_manager::VolumeManager; 274 using file_manager::VolumeInfo; 275 VolumeManager* volume_manager = VolumeManager::Get(GetProfile()); 276 if (!volume_manager) 277 return false; 278 279 VolumeInfo volume_info; 280 if (!volume_manager->FindVolumeInfoById(params->volume_id, &volume_info)) { 281 DidFail(base::File::FILE_ERROR_NOT_FOUND); 282 return false; 283 } 284 285 scoped_refptr<fileapi::FileSystemContext> file_system_context = 286 file_manager::util::GetFileSystemContextForRenderViewHost( 287 GetProfile(), render_view_host()); 288 289 // Set up file permission access. 290 const int child_id = render_view_host()->GetProcess()->GetID(); 291 if (!SetupFileSystemAccessPermissions(file_system_context, 292 child_id, 293 GetProfile(), 294 GetExtension())) { 295 DidFail(base::File::FILE_ERROR_SECURITY); 296 return false; 297 } 298 299 FileDefinition file_definition; 300 if (!file_manager::util::ConvertAbsoluteFilePathToRelativeFileSystemPath( 301 GetProfile(), 302 extension_id(), 303 volume_info.mount_path, 304 &file_definition.virtual_path)) { 305 DidFail(base::File::FILE_ERROR_INVALID_OPERATION); 306 return false; 307 } 308 file_definition.is_directory = true; 309 310 file_manager::util::ConvertFileDefinitionToEntryDefinition( 311 GetProfile(), 312 extension_id(), 313 file_definition, 314 base::Bind( 315 &FileBrowserPrivateRequestFileSystemFunction::OnEntryDefinition, 316 this)); 317 return true; 318 } 319 320 void FileBrowserPrivateRequestFileSystemFunction::OnEntryDefinition( 321 const EntryDefinition& entry_definition) { 322 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 323 324 if (entry_definition.error != base::File::FILE_OK) { 325 DidFail(entry_definition.error); 326 return; 327 } 328 329 if (!entry_definition.is_directory) { 330 DidFail(base::File::FILE_ERROR_NOT_A_DIRECTORY); 331 return; 332 } 333 334 base::DictionaryValue* dict = new base::DictionaryValue(); 335 SetResult(dict); 336 dict->SetString("name", entry_definition.file_system_name); 337 dict->SetString("root_url", entry_definition.file_system_root_url); 338 dict->SetInteger("error", drive::FILE_ERROR_OK); 339 SendResponse(true); 340 } 341 342 void FileWatchFunctionBase::Respond(bool success) { 343 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 344 345 SetResult(base::Value::CreateBooleanValue(success)); 346 SendResponse(success); 347 } 348 349 bool FileWatchFunctionBase::RunAsync() { 350 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 351 352 if (!render_view_host() || !render_view_host()->GetProcess()) 353 return false; 354 355 // First param is url of a file to watch. 356 std::string url; 357 if (!args_->GetString(0, &url) || url.empty()) 358 return false; 359 360 scoped_refptr<fileapi::FileSystemContext> file_system_context = 361 file_manager::util::GetFileSystemContextForRenderViewHost( 362 GetProfile(), render_view_host()); 363 364 FileSystemURL file_watch_url = file_system_context->CrackURL(GURL(url)); 365 base::FilePath local_path = file_watch_url.path(); 366 base::FilePath virtual_path = file_watch_url.virtual_path(); 367 if (local_path.empty()) { 368 Respond(false); 369 return true; 370 } 371 PerformFileWatchOperation(local_path, virtual_path, extension_id()); 372 373 return true; 374 } 375 376 void FileBrowserPrivateAddFileWatchFunction::PerformFileWatchOperation( 377 const base::FilePath& local_path, 378 const base::FilePath& virtual_path, 379 const std::string& extension_id) { 380 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 381 382 file_manager::EventRouter* event_router = 383 file_manager::FileBrowserPrivateAPI::Get(GetProfile())->event_router(); 384 event_router->AddFileWatch( 385 local_path, 386 virtual_path, 387 extension_id, 388 base::Bind(&FileBrowserPrivateAddFileWatchFunction::Respond, this)); 389 } 390 391 void FileBrowserPrivateRemoveFileWatchFunction::PerformFileWatchOperation( 392 const base::FilePath& local_path, 393 const base::FilePath& unused, 394 const std::string& extension_id) { 395 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 396 397 file_manager::EventRouter* event_router = 398 file_manager::FileBrowserPrivateAPI::Get(GetProfile())->event_router(); 399 event_router->RemoveFileWatch(local_path, extension_id); 400 Respond(true); 401 } 402 403 bool FileBrowserPrivateGetSizeStatsFunction::RunAsync() { 404 using extensions::api::file_browser_private::GetSizeStats::Params; 405 const scoped_ptr<Params> params(Params::Create(*args_)); 406 EXTENSION_FUNCTION_VALIDATE(params); 407 408 using file_manager::VolumeManager; 409 using file_manager::VolumeInfo; 410 VolumeManager* volume_manager = VolumeManager::Get(GetProfile()); 411 if (!volume_manager) 412 return false; 413 414 VolumeInfo volume_info; 415 if (!volume_manager->FindVolumeInfoById(params->volume_id, &volume_info)) 416 return false; 417 418 if (volume_info.type == file_manager::VOLUME_TYPE_GOOGLE_DRIVE) { 419 drive::FileSystemInterface* file_system = 420 drive::util::GetFileSystemByProfile(GetProfile()); 421 if (!file_system) { 422 // |file_system| is NULL if Drive is disabled. 423 // If stats couldn't be gotten for drive, result should be left 424 // undefined. See comments in GetDriveAvailableSpaceCallback(). 425 SendResponse(true); 426 return true; 427 } 428 429 file_system->GetAvailableSpace( 430 base::Bind(&FileBrowserPrivateGetSizeStatsFunction:: 431 GetDriveAvailableSpaceCallback, 432 this)); 433 } else { 434 uint64* total_size = new uint64(0); 435 uint64* remaining_size = new uint64(0); 436 BrowserThread::PostBlockingPoolTaskAndReply( 437 FROM_HERE, 438 base::Bind(&GetSizeStatsOnBlockingPool, 439 volume_info.mount_path.value(), 440 total_size, 441 remaining_size), 442 base::Bind(&FileBrowserPrivateGetSizeStatsFunction:: 443 GetSizeStatsCallback, 444 this, 445 base::Owned(total_size), 446 base::Owned(remaining_size))); 447 } 448 return true; 449 } 450 451 void FileBrowserPrivateGetSizeStatsFunction::GetDriveAvailableSpaceCallback( 452 drive::FileError error, 453 int64 bytes_total, 454 int64 bytes_used) { 455 if (error == drive::FILE_ERROR_OK) { 456 const uint64 bytes_total_unsigned = bytes_total; 457 const uint64 bytes_remaining_unsigned = bytes_total - bytes_used; 458 GetSizeStatsCallback(&bytes_total_unsigned, 459 &bytes_remaining_unsigned); 460 } else { 461 // If stats couldn't be gotten for drive, result should be left undefined. 462 SendResponse(true); 463 } 464 } 465 466 void FileBrowserPrivateGetSizeStatsFunction::GetSizeStatsCallback( 467 const uint64* total_size, 468 const uint64* remaining_size) { 469 base::DictionaryValue* sizes = new base::DictionaryValue(); 470 SetResult(sizes); 471 472 sizes->SetDouble("totalSize", static_cast<double>(*total_size)); 473 sizes->SetDouble("remainingSize", static_cast<double>(*remaining_size)); 474 475 SendResponse(true); 476 } 477 478 bool FileBrowserPrivateValidatePathNameLengthFunction::RunAsync() { 479 using extensions::api::file_browser_private::ValidatePathNameLength::Params; 480 const scoped_ptr<Params> params(Params::Create(*args_)); 481 EXTENSION_FUNCTION_VALIDATE(params); 482 483 scoped_refptr<fileapi::FileSystemContext> file_system_context = 484 file_manager::util::GetFileSystemContextForRenderViewHost( 485 GetProfile(), render_view_host()); 486 487 fileapi::FileSystemURL filesystem_url( 488 file_system_context->CrackURL(GURL(params->parent_directory_url))); 489 if (!chromeos::FileSystemBackend::CanHandleURL(filesystem_url)) 490 return false; 491 492 // No explicit limit on the length of Drive file names. 493 if (filesystem_url.type() == fileapi::kFileSystemTypeDrive) { 494 SetResult(new base::FundamentalValue(true)); 495 SendResponse(true); 496 return true; 497 } 498 499 base::PostTaskAndReplyWithResult( 500 BrowserThread::GetBlockingPool(), 501 FROM_HERE, 502 base::Bind(&GetFileNameMaxLengthOnBlockingPool, 503 filesystem_url.path().AsUTF8Unsafe()), 504 base::Bind(&FileBrowserPrivateValidatePathNameLengthFunction:: 505 OnFilePathLimitRetrieved, 506 this, params->name.size())); 507 return true; 508 } 509 510 void FileBrowserPrivateValidatePathNameLengthFunction::OnFilePathLimitRetrieved( 511 size_t current_length, 512 size_t max_length) { 513 SetResult(new base::FundamentalValue(current_length <= max_length)); 514 SendResponse(true); 515 } 516 517 bool FileBrowserPrivateFormatVolumeFunction::RunAsync() { 518 using extensions::api::file_browser_private::FormatVolume::Params; 519 const scoped_ptr<Params> params(Params::Create(*args_)); 520 EXTENSION_FUNCTION_VALIDATE(params); 521 522 using file_manager::VolumeManager; 523 using file_manager::VolumeInfo; 524 VolumeManager* volume_manager = VolumeManager::Get(GetProfile()); 525 if (!volume_manager) 526 return false; 527 528 VolumeInfo volume_info; 529 if (!volume_manager->FindVolumeInfoById(params->volume_id, &volume_info)) 530 return false; 531 532 DiskMountManager::GetInstance()->FormatMountedDevice( 533 volume_info.mount_path.AsUTF8Unsafe()); 534 SendResponse(true); 535 return true; 536 } 537 538 bool FileBrowserPrivateStartCopyFunction::RunAsync() { 539 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 540 541 using extensions::api::file_browser_private::StartCopy::Params; 542 const scoped_ptr<Params> params(Params::Create(*args_)); 543 EXTENSION_FUNCTION_VALIDATE(params); 544 545 if (params->source_url.empty() || params->parent.empty() || 546 params->new_name.empty()) { 547 // Error code in format of DOMError.name. 548 SetError("EncodingError"); 549 return false; 550 } 551 552 scoped_refptr<fileapi::FileSystemContext> file_system_context = 553 file_manager::util::GetFileSystemContextForRenderViewHost( 554 GetProfile(), render_view_host()); 555 556 // |parent| may have a trailing slash if it is a root directory. 557 std::string destination_url_string = params->parent; 558 if (destination_url_string[destination_url_string.size() - 1] != '/') 559 destination_url_string += '/'; 560 destination_url_string += net::EscapePath(params->new_name); 561 562 fileapi::FileSystemURL source_url( 563 file_system_context->CrackURL(GURL(params->source_url))); 564 fileapi::FileSystemURL destination_url( 565 file_system_context->CrackURL(GURL(destination_url_string))); 566 567 if (!source_url.is_valid() || !destination_url.is_valid()) { 568 // Error code in format of DOMError.name. 569 SetError("EncodingError"); 570 return false; 571 } 572 573 return BrowserThread::PostTaskAndReplyWithResult( 574 BrowserThread::IO, 575 FROM_HERE, 576 base::Bind(&StartCopyOnIOThread, 577 GetProfile(), 578 file_system_context, 579 source_url, 580 destination_url), 581 base::Bind(&FileBrowserPrivateStartCopyFunction::RunAfterStartCopy, 582 this)); 583 } 584 585 void FileBrowserPrivateStartCopyFunction::RunAfterStartCopy( 586 int operation_id) { 587 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 588 589 SetResult(base::Value::CreateIntegerValue(operation_id)); 590 SendResponse(true); 591 } 592 593 bool FileBrowserPrivateCancelCopyFunction::RunAsync() { 594 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 595 596 using extensions::api::file_browser_private::CancelCopy::Params; 597 const scoped_ptr<Params> params(Params::Create(*args_)); 598 EXTENSION_FUNCTION_VALIDATE(params); 599 600 scoped_refptr<fileapi::FileSystemContext> file_system_context = 601 file_manager::util::GetFileSystemContextForRenderViewHost( 602 GetProfile(), render_view_host()); 603 604 // We don't much take care about the result of cancellation. 605 BrowserThread::PostTask( 606 BrowserThread::IO, 607 FROM_HERE, 608 base::Bind(&CancelCopyOnIOThread, file_system_context, params->copy_id)); 609 SendResponse(true); 610 return true; 611 } 612 613 bool FileBrowserPrivateInternalResolveIsolatedEntriesFunction::RunAsync() { 614 using extensions::api::file_browser_private_internal::ResolveIsolatedEntries:: 615 Params; 616 const scoped_ptr<Params> params(Params::Create(*args_)); 617 EXTENSION_FUNCTION_VALIDATE(params); 618 619 scoped_refptr<fileapi::FileSystemContext> file_system_context = 620 file_manager::util::GetFileSystemContextForRenderViewHost( 621 GetProfile(), render_view_host()); 622 DCHECK(file_system_context); 623 624 const fileapi::ExternalFileSystemBackend* external_backend = 625 file_system_context->external_backend(); 626 DCHECK(external_backend); 627 628 file_manager::util::FileDefinitionList file_definition_list; 629 for (size_t i = 0; i < params->urls.size(); ++i) { 630 FileSystemURL fileSystemUrl = 631 file_system_context->CrackURL(GURL(params->urls[i])); 632 DCHECK(external_backend->CanHandleType(fileSystemUrl.type())); 633 634 FileDefinition file_definition; 635 const bool result = 636 file_manager::util::ConvertAbsoluteFilePathToRelativeFileSystemPath( 637 GetProfile(), 638 extension_->id(), 639 fileSystemUrl.path(), 640 &file_definition.virtual_path); 641 if (!result) 642 continue; 643 // The API only supports isolated files. 644 file_definition.is_directory = false; 645 file_definition_list.push_back(file_definition); 646 } 647 648 file_manager::util::ConvertFileDefinitionListToEntryDefinitionList( 649 GetProfile(), 650 extension_->id(), 651 file_definition_list, // Safe, since copied internally. 652 base::Bind( 653 &FileBrowserPrivateInternalResolveIsolatedEntriesFunction:: 654 RunAsyncAfterConvertFileDefinitionListToEntryDefinitionList, 655 this)); 656 return true; 657 } 658 659 void FileBrowserPrivateInternalResolveIsolatedEntriesFunction:: 660 RunAsyncAfterConvertFileDefinitionListToEntryDefinitionList(scoped_ptr< 661 file_manager::util::EntryDefinitionList> entry_definition_list) { 662 using extensions::api::file_browser_private_internal::EntryDescription; 663 std::vector<linked_ptr<EntryDescription> > entries; 664 665 for (size_t i = 0; i < entry_definition_list->size(); ++i) { 666 if (entry_definition_list->at(i).error != base::File::FILE_OK) 667 continue; 668 linked_ptr<EntryDescription> entry(new EntryDescription); 669 entry->file_system_name = entry_definition_list->at(i).file_system_name; 670 entry->file_system_root = entry_definition_list->at(i).file_system_root_url; 671 entry->file_full_path = 672 "/" + entry_definition_list->at(i).full_path.AsUTF8Unsafe(); 673 entry->file_is_directory = entry_definition_list->at(i).is_directory; 674 entries.push_back(entry); 675 } 676 677 results_ = extensions::api::file_browser_private_internal:: 678 ResolveIsolatedEntries::Results::Create(entries); 679 SendResponse(true); 680 } 681 } // namespace extensions 682