private_api_file_system.cc revision d0247b1b59f9c528cb6df88b4f2b9afaf80d181e
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/stat.h> 8#include <sys/statvfs.h> 9#include <sys/types.h> 10#include <utime.h> 11 12#include "base/path_service.h" 13#include "base/posix/eintr_wrapper.h" 14#include "base/strings/string_number_conversions.h" 15#include "base/strings/stringprintf.h" 16#include "base/task_runner_util.h" 17#include "base/threading/sequenced_worker_pool.h" 18#include "chrome/browser/browser_process.h" 19#include "chrome/browser/chromeos/drive/drive.pb.h" 20#include "chrome/browser/chromeos/drive/file_system_interface.h" 21#include "chrome/browser/chromeos/drive/file_system_util.h" 22#include "chrome/browser/chromeos/extensions/file_manager/event_router.h" 23#include "chrome/browser/chromeos/extensions/file_manager/file_browser_private_api.h" 24#include "chrome/browser/chromeos/extensions/file_manager/private_api_util.h" 25#include "chrome/browser/chromeos/file_manager/fileapi_util.h" 26#include "chrome/browser/chromeos/fileapi/file_system_backend.h" 27#include "chrome/browser/profiles/profile.h" 28#include "chrome/browser/profiles/profile_manager.h" 29#include "chrome/common/extensions/api/file_browser_private.h" 30#include "chromeos/disks/disk_mount_manager.h" 31#include "content/public/browser/browser_context.h" 32#include "content/public/browser/child_process_security_policy.h" 33#include "content/public/browser/render_process_host.h" 34#include "content/public/browser/render_view_host.h" 35#include "content/public/browser/storage_partition.h" 36#include "webkit/browser/fileapi/file_system_context.h" 37#include "webkit/browser/fileapi/file_system_file_util.h" 38#include "webkit/browser/fileapi/file_system_operation_context.h" 39#include "webkit/browser/fileapi/file_system_operation_runner.h" 40#include "webkit/browser/fileapi/file_system_url.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// Sets last modified date. 168bool SetLastModifiedOnBlockingPool(const base::FilePath& local_path, 169 time_t timestamp) { 170 if (local_path.empty()) 171 return false; 172 173 struct stat stat_buffer; 174 if (stat(local_path.value().c_str(), &stat_buffer) != 0) 175 return false; 176 177 struct utimbuf times; 178 times.actime = stat_buffer.st_atime; 179 times.modtime = timestamp; 180 return utime(local_path.value().c_str(), ×) == 0; 181} 182 183// Returns EventRouter for the |profile_id| if available. 184file_manager::EventRouter* GetEventRouterByProfileId(void* profile_id) { 185 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 186 187 // |profile_id| needs to be checked with ProfileManager::IsValidProfile 188 // before using it. 189 Profile* profile = reinterpret_cast<Profile*>(profile_id); 190 if (!g_browser_process->profile_manager()->IsValidProfile(profile)) 191 return NULL; 192 193 return file_manager::FileBrowserPrivateAPI::Get(profile)->event_router(); 194} 195 196// Notifies the copy progress to extensions via event router. 197void NotifyCopyProgress( 198 void* profile_id, 199 fileapi::FileSystemOperationRunner::OperationID operation_id, 200 fileapi::FileSystemOperation::CopyProgressType type, 201 const FileSystemURL& url, 202 int64 size) { 203 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 204 205 file_manager::EventRouter* event_router = 206 GetEventRouterByProfileId(profile_id); 207 if (event_router) { 208 event_router->OnCopyProgress( 209 operation_id, type, url.ToGURL(), size); 210 } 211} 212 213// Callback invoked periodically on progress update of Copy(). 214void OnCopyProgress( 215 void* profile_id, 216 fileapi::FileSystemOperationRunner::OperationID* operation_id, 217 fileapi::FileSystemOperation::CopyProgressType type, 218 const FileSystemURL& url, 219 int64 size) { 220 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 221 222 BrowserThread::PostTask( 223 BrowserThread::UI, FROM_HERE, 224 base::Bind(&NotifyCopyProgress, 225 profile_id, *operation_id, type, url, size)); 226} 227 228// Notifies the copy completion to extensions via event router. 229void NotifyCopyCompletion( 230 void* profile_id, 231 fileapi::FileSystemOperationRunner::OperationID operation_id, 232 const FileSystemURL& dest_url, 233 base::PlatformFileError error) { 234 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 235 236 file_manager::EventRouter* event_router = 237 GetEventRouterByProfileId(profile_id); 238 if (event_router) 239 event_router->OnCopyCompleted(operation_id, dest_url.ToGURL(), error); 240} 241 242// Callback invoked upon completion of Copy() (regardless of succeeded or 243// failed). 244void OnCopyCompleted( 245 void* profile_id, 246 fileapi::FileSystemOperationRunner::OperationID* operation_id, 247 const FileSystemURL& dest_url, 248 base::PlatformFileError error) { 249 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 250 251 BrowserThread::PostTask( 252 BrowserThread::UI, FROM_HERE, 253 base::Bind(&NotifyCopyCompletion, 254 profile_id, *operation_id, dest_url, error)); 255} 256 257// Starts the copy operation via FileSystemOperationRunner. 258fileapi::FileSystemOperationRunner::OperationID StartCopyOnIOThread( 259 void* profile_id, 260 scoped_refptr<fileapi::FileSystemContext> file_system_context, 261 const FileSystemURL& source_url, 262 const FileSystemURL& dest_url) { 263 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 264 265 // Note: |operation_id| is owned by the callback for 266 // FileSystemOperationRunner::Copy(). It is always called in the next message 267 // loop or later, so at least during this invocation it should alive. 268 fileapi::FileSystemOperationRunner::OperationID* operation_id = 269 new fileapi::FileSystemOperationRunner::OperationID; 270 *operation_id = file_system_context->operation_runner()->Copy( 271 source_url, dest_url, 272 base::Bind(&OnCopyProgress, 273 profile_id, base::Unretained(operation_id)), 274 base::Bind(&OnCopyCompleted, 275 profile_id, base::Owned(operation_id), dest_url)); 276 return *operation_id; 277} 278 279void OnCopyCancelled(base::PlatformFileError error) { 280 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 281 282 // We just ignore the status if the copy is actually cancelled or not, 283 // because failing cancellation means the operation is not running now. 284 DLOG_IF(WARNING, error != base::PLATFORM_FILE_OK) 285 << "Failed to cancel copy: " << error; 286} 287 288// Cancels the running copy operation identified by |operation_id|. 289void CancelCopyOnIOThread( 290 scoped_refptr<fileapi::FileSystemContext> file_system_context, 291 fileapi::FileSystemOperationRunner::OperationID operation_id) { 292 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 293 294 file_system_context->operation_runner()->Cancel( 295 operation_id, base::Bind(&OnCopyCancelled)); 296} 297 298} // namespace 299 300void FileBrowserPrivateRequestFileSystemFunction::DidOpenFileSystem( 301 scoped_refptr<fileapi::FileSystemContext> file_system_context, 302 base::PlatformFileError result, 303 const std::string& name, 304 const GURL& root_url) { 305 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 306 307 if (result != base::PLATFORM_FILE_OK) { 308 DidFail(result); 309 return; 310 } 311 312 // RenderViewHost may have gone while the task is posted asynchronously. 313 if (!render_view_host()) { 314 DidFail(base::PLATFORM_FILE_ERROR_FAILED); 315 return; 316 } 317 318 // Set up file permission access. 319 const int child_id = render_view_host()->GetProcess()->GetID(); 320 if (!SetupFileSystemAccessPermissions(file_system_context, 321 child_id, 322 GetExtension())) { 323 DidFail(base::PLATFORM_FILE_ERROR_SECURITY); 324 return; 325 } 326 327 // Set permissions for the Drive mount point immediately when we kick of 328 // first instance of file manager. The actual mount event will be sent to 329 // UI only when we perform proper authentication. 330 // 331 // Note that we call this function even when Drive is disabled by the 332 // setting. Otherwise, we need to call this when the setting is changed at 333 // a later time, which complicates the code. 334 SetDriveMountPointPermissions(profile_, extension_id(), render_view_host()); 335 336 DictionaryValue* dict = new DictionaryValue(); 337 SetResult(dict); 338 dict->SetString("name", name); 339 dict->SetString("root_url", root_url.spec()); 340 dict->SetInteger("error", drive::FILE_ERROR_OK); 341 SendResponse(true); 342} 343 344void FileBrowserPrivateRequestFileSystemFunction::DidFail( 345 base::PlatformFileError error_code) { 346 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 347 348 error_ = base::StringPrintf(kFileError, static_cast<int>(error_code)); 349 SendResponse(false); 350} 351 352bool FileBrowserPrivateRequestFileSystemFunction:: 353 SetupFileSystemAccessPermissions( 354 scoped_refptr<fileapi::FileSystemContext> file_system_context, 355 int child_id, 356 scoped_refptr<const extensions::Extension> extension) { 357 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 358 359 if (!extension.get()) 360 return false; 361 362 // Make sure that only component extension can access the entire 363 // local file system. 364 if (extension_->location() != extensions::Manifest::COMPONENT) { 365 NOTREACHED() << "Private method access by non-component extension " 366 << extension->id(); 367 return false; 368 } 369 370 fileapi::ExternalFileSystemBackend* backend = 371 file_system_context->external_backend(); 372 if (!backend) 373 return false; 374 375 // Grant full access to File API from this component extension. 376 backend->GrantFullAccessToExtension(extension_->id()); 377 378 // Grant R/W file permissions to the renderer hosting component 379 // extension for all paths exposed by our local file system backend. 380 std::vector<base::FilePath> root_dirs = backend->GetRootDirectories(); 381 for (size_t i = 0; i < root_dirs.size(); ++i) { 382 ChildProcessSecurityPolicy::GetInstance()->GrantCreateReadWriteFile( 383 child_id, root_dirs[i]); 384 } 385 return true; 386} 387 388bool FileBrowserPrivateRequestFileSystemFunction::RunImpl() { 389 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 390 using extensions::api::file_browser_private::RequestFileSystem::Params; 391 const scoped_ptr<Params> params(Params::Create(*args_)); 392 EXTENSION_FUNCTION_VALIDATE(params); 393 394 // TODO(satorux): Handle the file system ID. crbug.com/284963. 395 DCHECK_EQ("compatible", params->file_system_id); 396 397 if (!dispatcher() || !render_view_host() || !render_view_host()->GetProcess()) 398 return false; 399 400 set_log_on_completion(true); 401 402 scoped_refptr<fileapi::FileSystemContext> file_system_context = 403 file_manager::util::GetFileSystemContextForRenderViewHost( 404 profile(), render_view_host()); 405 406 const GURL origin_url = source_url_.GetOrigin(); 407 file_system_context->OpenFileSystem( 408 origin_url, 409 fileapi::kFileSystemTypeExternal, 410 fileapi::OPEN_FILE_SYSTEM_FAIL_IF_NONEXISTENT, 411 base::Bind(&FileBrowserPrivateRequestFileSystemFunction:: 412 DidOpenFileSystem, 413 this, 414 file_system_context)); 415 return true; 416} 417 418void FileWatchFunctionBase::Respond(bool success) { 419 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 420 421 SetResult(Value::CreateBooleanValue(success)); 422 SendResponse(success); 423} 424 425bool FileWatchFunctionBase::RunImpl() { 426 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 427 428 if (!render_view_host() || !render_view_host()->GetProcess()) 429 return false; 430 431 // First param is url of a file to watch. 432 std::string url; 433 if (!args_->GetString(0, &url) || url.empty()) 434 return false; 435 436 scoped_refptr<fileapi::FileSystemContext> file_system_context = 437 file_manager::util::GetFileSystemContextForRenderViewHost( 438 profile(), render_view_host()); 439 440 FileSystemURL file_watch_url = file_system_context->CrackURL(GURL(url)); 441 base::FilePath local_path = file_watch_url.path(); 442 base::FilePath virtual_path = file_watch_url.virtual_path(); 443 if (local_path.empty()) { 444 Respond(false); 445 return true; 446 } 447 PerformFileWatchOperation(local_path, virtual_path, extension_id()); 448 449 return true; 450} 451 452void FileBrowserPrivateAddFileWatchFunction::PerformFileWatchOperation( 453 const base::FilePath& local_path, 454 const base::FilePath& virtual_path, 455 const std::string& extension_id) { 456 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 457 458 file_manager::EventRouter* event_router = 459 file_manager::FileBrowserPrivateAPI::Get(profile_)->event_router(); 460 event_router->AddFileWatch( 461 local_path, 462 virtual_path, 463 extension_id, 464 base::Bind(&FileBrowserPrivateAddFileWatchFunction::Respond, this)); 465} 466 467void FileBrowserPrivateRemoveFileWatchFunction::PerformFileWatchOperation( 468 const base::FilePath& local_path, 469 const base::FilePath& unused, 470 const std::string& extension_id) { 471 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 472 473 file_manager::EventRouter* event_router = 474 file_manager::FileBrowserPrivateAPI::Get(profile_)->event_router(); 475 event_router->RemoveFileWatch(local_path, extension_id); 476 Respond(true); 477} 478 479bool FileBrowserPrivateSetLastModifiedFunction::RunImpl() { 480 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 481 using extensions::api::file_browser_private::SetLastModified::Params; 482 const scoped_ptr<Params> params(Params::Create(*args_)); 483 EXTENSION_FUNCTION_VALIDATE(params); 484 485 base::FilePath local_path = file_manager::util::GetLocalPathFromURL( 486 render_view_host(), profile(), GURL(params->file_url)); 487 488 base::PostTaskAndReplyWithResult( 489 BrowserThread::GetBlockingPool(), 490 FROM_HERE, 491 base::Bind(&SetLastModifiedOnBlockingPool, 492 local_path, 493 strtoul(params->last_modified.c_str(), NULL, 0)), 494 base::Bind(&FileBrowserPrivateSetLastModifiedFunction::SendResponse, 495 this)); 496 return true; 497} 498 499bool FileBrowserPrivateGetSizeStatsFunction::RunImpl() { 500 using extensions::api::file_browser_private::GetSizeStats::Params; 501 const scoped_ptr<Params> params(Params::Create(*args_)); 502 EXTENSION_FUNCTION_VALIDATE(params); 503 504 base::FilePath file_path = file_manager::util::GetLocalPathFromURL( 505 render_view_host(), profile(), GURL(params->mount_path)); 506 if (file_path.empty()) 507 return false; 508 509 if (file_path == drive::util::GetDriveMountPointPath()) { 510 drive::FileSystemInterface* file_system = 511 drive::util::GetFileSystemByProfile(profile()); 512 if (!file_system) { 513 // |file_system| is NULL if Drive is disabled. 514 // If stats couldn't be gotten for drive, result should be left 515 // undefined. See comments in GetDriveAvailableSpaceCallback(). 516 SendResponse(true); 517 return true; 518 } 519 520 file_system->GetAvailableSpace( 521 base::Bind(&FileBrowserPrivateGetSizeStatsFunction:: 522 GetDriveAvailableSpaceCallback, 523 this)); 524 } else { 525 uint64* total_size = new uint64(0); 526 uint64* remaining_size = new uint64(0); 527 BrowserThread::PostBlockingPoolTaskAndReply( 528 FROM_HERE, 529 base::Bind(&GetSizeStatsOnBlockingPool, 530 file_path.value(), 531 total_size, 532 remaining_size), 533 base::Bind(&FileBrowserPrivateGetSizeStatsFunction:: 534 GetSizeStatsCallback, 535 this, 536 base::Owned(total_size), 537 base::Owned(remaining_size))); 538 } 539 return true; 540} 541 542void FileBrowserPrivateGetSizeStatsFunction::GetDriveAvailableSpaceCallback( 543 drive::FileError error, 544 int64 bytes_total, 545 int64 bytes_used) { 546 if (error == drive::FILE_ERROR_OK) { 547 const uint64 bytes_total_unsigned = bytes_total; 548 const uint64 bytes_remaining_unsigned = bytes_total - bytes_used; 549 GetSizeStatsCallback(&bytes_total_unsigned, 550 &bytes_remaining_unsigned); 551 } else { 552 // If stats couldn't be gotten for drive, result should be left undefined. 553 SendResponse(true); 554 } 555} 556 557void FileBrowserPrivateGetSizeStatsFunction::GetSizeStatsCallback( 558 const uint64* total_size, 559 const uint64* remaining_size) { 560 base::DictionaryValue* sizes = new base::DictionaryValue(); 561 SetResult(sizes); 562 563 sizes->SetDouble("totalSize", static_cast<double>(*total_size)); 564 sizes->SetDouble("remainingSize", static_cast<double>(*remaining_size)); 565 566 SendResponse(true); 567} 568 569bool FileBrowserPrivateGetVolumeMetadataFunction::RunImpl() { 570 using extensions::api::file_browser_private::GetVolumeMetadata::Params; 571 const scoped_ptr<Params> params(Params::Create(*args_)); 572 EXTENSION_FUNCTION_VALIDATE(params); 573 574 base::FilePath file_path = file_manager::util::GetLocalPathFromURL( 575 render_view_host(), profile(), GURL(params->mount_url)); 576 if (file_path.empty()) { 577 error_ = "Invalid mount path."; 578 return false; 579 } 580 581 results_.reset(); 582 583 base::FilePath home_path; 584 // TODO(hidehiko): Return the volume info for Drive File System. 585 if (PathService::Get(base::DIR_HOME, &home_path) && 586 file_path == home_path.AppendASCII("Downloads")) { 587 // Return simple (fake) volume metadata for Downloads volume. 588 SetResult(CreateDownloadsVolumeMetadata()); 589 } else { 590 const DiskMountManager::Disk* volume = GetVolumeAsDisk(file_path.value()); 591 if (volume) 592 SetResult(CreateValueFromDisk(profile_, extension_->id(), volume)); 593 } 594 595 SendResponse(true); 596 return true; 597} 598 599bool FileBrowserPrivateValidatePathNameLengthFunction::RunImpl() { 600 using extensions::api::file_browser_private::ValidatePathNameLength::Params; 601 const scoped_ptr<Params> params(Params::Create(*args_)); 602 EXTENSION_FUNCTION_VALIDATE(params); 603 604 scoped_refptr<fileapi::FileSystemContext> file_system_context = 605 file_manager::util::GetFileSystemContextForRenderViewHost( 606 profile(), render_view_host()); 607 608 fileapi::FileSystemURL filesystem_url( 609 file_system_context->CrackURL(GURL(params->parent_directory_url))); 610 if (!chromeos::FileSystemBackend::CanHandleURL(filesystem_url)) 611 return false; 612 613 // No explicit limit on the length of Drive file names. 614 if (filesystem_url.type() == fileapi::kFileSystemTypeDrive) { 615 SetResult(new base::FundamentalValue(true)); 616 SendResponse(true); 617 return true; 618 } 619 620 base::PostTaskAndReplyWithResult( 621 BrowserThread::GetBlockingPool(), 622 FROM_HERE, 623 base::Bind(&GetFileNameMaxLengthOnBlockingPool, 624 filesystem_url.path().AsUTF8Unsafe()), 625 base::Bind(&FileBrowserPrivateValidatePathNameLengthFunction:: 626 OnFilePathLimitRetrieved, 627 this, params->name.size())); 628 return true; 629} 630 631void FileBrowserPrivateValidatePathNameLengthFunction::OnFilePathLimitRetrieved( 632 size_t current_length, 633 size_t max_length) { 634 SetResult(new base::FundamentalValue(current_length <= max_length)); 635 SendResponse(true); 636} 637 638bool FileBrowserPrivateFormatDeviceFunction::RunImpl() { 639 using extensions::api::file_browser_private::FormatDevice::Params; 640 const scoped_ptr<Params> params(Params::Create(*args_)); 641 EXTENSION_FUNCTION_VALIDATE(params); 642 643 base::FilePath file_path = file_manager::util::GetLocalPathFromURL( 644 render_view_host(), profile(), GURL(params->mount_path)); 645 if (file_path.empty()) 646 return false; 647 648 DiskMountManager::GetInstance()->FormatMountedDevice(file_path.value()); 649 SendResponse(true); 650 return true; 651} 652 653bool FileBrowserPrivateStartCopyFunction::RunImpl() { 654 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 655 656 using extensions::api::file_browser_private::StartCopy::Params; 657 const scoped_ptr<Params> params(Params::Create(*args_)); 658 EXTENSION_FUNCTION_VALIDATE(params); 659 660 if (params->source_url.empty() || params->parent.empty() || 661 params->new_name.empty()) { 662 error_ = base::IntToString(fileapi::PlatformFileErrorToWebFileError( 663 base::PLATFORM_FILE_ERROR_INVALID_URL)); 664 return false; 665 } 666 667 scoped_refptr<fileapi::FileSystemContext> file_system_context = 668 file_manager::util::GetFileSystemContextForRenderViewHost( 669 profile(), render_view_host()); 670 671 fileapi::FileSystemURL source_url( 672 file_system_context->CrackURL(GURL(params->source_url))); 673 fileapi::FileSystemURL dest_url(file_system_context->CrackURL( 674 GURL(params->parent + "/" + params->new_name))); 675 676 if (!source_url.is_valid() || !dest_url.is_valid()) { 677 error_ = base::IntToString(fileapi::PlatformFileErrorToWebFileError( 678 base::PLATFORM_FILE_ERROR_INVALID_URL)); 679 return false; 680 } 681 682 return BrowserThread::PostTaskAndReplyWithResult( 683 BrowserThread::IO, 684 FROM_HERE, 685 base::Bind(&StartCopyOnIOThread, 686 profile(), file_system_context, source_url, dest_url), 687 base::Bind(&FileBrowserPrivateStartCopyFunction::RunAfterStartCopy, 688 this)); 689} 690 691void FileBrowserPrivateStartCopyFunction::RunAfterStartCopy( 692 int operation_id) { 693 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 694 695 SetResult(Value::CreateIntegerValue(operation_id)); 696 SendResponse(true); 697} 698 699bool FileBrowserPrivateCancelCopyFunction::RunImpl() { 700 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 701 702 using extensions::api::file_browser_private::CancelCopy::Params; 703 const scoped_ptr<Params> params(Params::Create(*args_)); 704 EXTENSION_FUNCTION_VALIDATE(params); 705 706 scoped_refptr<fileapi::FileSystemContext> file_system_context = 707 file_manager::util::GetFileSystemContextForRenderViewHost( 708 profile(), render_view_host()); 709 710 // We don't much take care about the result of cancellation. 711 BrowserThread::PostTask( 712 BrowserThread::IO, 713 FROM_HERE, 714 base::Bind(&CancelCopyOnIOThread, file_system_context, params->copy_id)); 715 SendResponse(true); 716 return true; 717} 718 719} // namespace extensions 720