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