Home | History | Annotate | Download | only in file_manager
      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