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/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