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