- add sources.
[platform/framework/web/crosswalk.git] / src / chrome / browser / chromeos / extensions / file_manager / private_api_file_system.cc
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
44 using chromeos::disks::DiskMountManager;
45 using content::BrowserContext;
46 using content::BrowserThread;
47 using content::ChildProcessSecurityPolicy;
48 using content::WebContents;
49 using fileapi::FileSystemURL;
50
51 namespace extensions {
52 namespace {
53
54 // Error messages.
55 const char kFileError[] = "File error %d";
56
57 const 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
71 base::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
105 base::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).
115 void 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|.
142 void 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.
156 size_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.
168 file_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.
181 void 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().
200 void 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.
217 void 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).
235 void 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.
251 fileapi::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
274 void 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|.
284 void 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
295 void 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
303 bool 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
339 bool 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           GetProfile(), 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(
374       GetProfile(), extension_id(), render_view_host());
375
376   fileapi::FileSystemInfo info =
377       fileapi::GetFileSystemInfoForChromeOS(source_url_.GetOrigin());
378
379   DictionaryValue* dict = new DictionaryValue();
380   SetResult(dict);
381   dict->SetString("name", info.name);
382   dict->SetString("root_url", info.root_url.spec());
383   dict->SetInteger("error", drive::FILE_ERROR_OK);
384   SendResponse(true);
385   return true;
386 }
387
388 void FileWatchFunctionBase::Respond(bool success) {
389   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
390
391   SetResult(Value::CreateBooleanValue(success));
392   SendResponse(success);
393 }
394
395 bool FileWatchFunctionBase::RunImpl() {
396   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
397
398   if (!render_view_host() || !render_view_host()->GetProcess())
399     return false;
400
401   // First param is url of a file to watch.
402   std::string url;
403   if (!args_->GetString(0, &url) || url.empty())
404     return false;
405
406   scoped_refptr<fileapi::FileSystemContext> file_system_context =
407       file_manager::util::GetFileSystemContextForRenderViewHost(
408           GetProfile(), render_view_host());
409
410   FileSystemURL file_watch_url = file_system_context->CrackURL(GURL(url));
411   base::FilePath local_path = file_watch_url.path();
412   base::FilePath virtual_path = file_watch_url.virtual_path();
413   if (local_path.empty()) {
414     Respond(false);
415     return true;
416   }
417   PerformFileWatchOperation(local_path, virtual_path, extension_id());
418
419   return true;
420 }
421
422 void FileBrowserPrivateAddFileWatchFunction::PerformFileWatchOperation(
423     const base::FilePath& local_path,
424     const base::FilePath& virtual_path,
425     const std::string& extension_id) {
426   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
427
428   file_manager::EventRouter* event_router =
429       file_manager::FileBrowserPrivateAPI::Get(GetProfile())->event_router();
430   event_router->AddFileWatch(
431       local_path,
432       virtual_path,
433       extension_id,
434       base::Bind(&FileBrowserPrivateAddFileWatchFunction::Respond, this));
435 }
436
437 void FileBrowserPrivateRemoveFileWatchFunction::PerformFileWatchOperation(
438     const base::FilePath& local_path,
439     const base::FilePath& unused,
440     const std::string& extension_id) {
441   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
442
443   file_manager::EventRouter* event_router =
444       file_manager::FileBrowserPrivateAPI::Get(GetProfile())->event_router();
445   event_router->RemoveFileWatch(local_path, extension_id);
446   Respond(true);
447 }
448
449 bool FileBrowserPrivateGetSizeStatsFunction::RunImpl() {
450   using extensions::api::file_browser_private::GetSizeStats::Params;
451   const scoped_ptr<Params> params(Params::Create(*args_));
452   EXTENSION_FUNCTION_VALIDATE(params);
453
454   base::FilePath file_path = file_manager::util::GetLocalPathFromURL(
455       render_view_host(), GetProfile(), GURL(params->mount_path));
456   if (file_path.empty())
457     return false;
458
459   if (file_path == drive::util::GetDriveMountPointPath()) {
460     drive::FileSystemInterface* file_system =
461         drive::util::GetFileSystemByProfile(GetProfile());
462     if (!file_system) {
463       // |file_system| is NULL if Drive is disabled.
464       // If stats couldn't be gotten for drive, result should be left
465       // undefined. See comments in GetDriveAvailableSpaceCallback().
466       SendResponse(true);
467       return true;
468     }
469
470     file_system->GetAvailableSpace(
471         base::Bind(&FileBrowserPrivateGetSizeStatsFunction::
472                        GetDriveAvailableSpaceCallback,
473                    this));
474   } else {
475     uint64* total_size = new uint64(0);
476     uint64* remaining_size = new uint64(0);
477     BrowserThread::PostBlockingPoolTaskAndReply(
478         FROM_HERE,
479         base::Bind(&GetSizeStatsOnBlockingPool,
480                    file_path.value(),
481                    total_size,
482                    remaining_size),
483         base::Bind(&FileBrowserPrivateGetSizeStatsFunction::
484                        GetSizeStatsCallback,
485                    this,
486                    base::Owned(total_size),
487                    base::Owned(remaining_size)));
488   }
489   return true;
490 }
491
492 void FileBrowserPrivateGetSizeStatsFunction::GetDriveAvailableSpaceCallback(
493     drive::FileError error,
494     int64 bytes_total,
495     int64 bytes_used) {
496   if (error == drive::FILE_ERROR_OK) {
497     const uint64 bytes_total_unsigned = bytes_total;
498     const uint64 bytes_remaining_unsigned = bytes_total - bytes_used;
499     GetSizeStatsCallback(&bytes_total_unsigned,
500                          &bytes_remaining_unsigned);
501   } else {
502     // If stats couldn't be gotten for drive, result should be left undefined.
503     SendResponse(true);
504   }
505 }
506
507 void FileBrowserPrivateGetSizeStatsFunction::GetSizeStatsCallback(
508     const uint64* total_size,
509     const uint64* remaining_size) {
510   base::DictionaryValue* sizes = new base::DictionaryValue();
511   SetResult(sizes);
512
513   sizes->SetDouble("totalSize", static_cast<double>(*total_size));
514   sizes->SetDouble("remainingSize", static_cast<double>(*remaining_size));
515
516   SendResponse(true);
517 }
518
519 bool FileBrowserPrivateValidatePathNameLengthFunction::RunImpl() {
520   using extensions::api::file_browser_private::ValidatePathNameLength::Params;
521   const scoped_ptr<Params> params(Params::Create(*args_));
522   EXTENSION_FUNCTION_VALIDATE(params);
523
524   scoped_refptr<fileapi::FileSystemContext> file_system_context =
525       file_manager::util::GetFileSystemContextForRenderViewHost(
526           GetProfile(), render_view_host());
527
528   fileapi::FileSystemURL filesystem_url(
529       file_system_context->CrackURL(GURL(params->parent_directory_url)));
530   if (!chromeos::FileSystemBackend::CanHandleURL(filesystem_url))
531     return false;
532
533   // No explicit limit on the length of Drive file names.
534   if (filesystem_url.type() == fileapi::kFileSystemTypeDrive) {
535     SetResult(new base::FundamentalValue(true));
536     SendResponse(true);
537     return true;
538   }
539
540   base::PostTaskAndReplyWithResult(
541       BrowserThread::GetBlockingPool(),
542       FROM_HERE,
543       base::Bind(&GetFileNameMaxLengthOnBlockingPool,
544                  filesystem_url.path().AsUTF8Unsafe()),
545       base::Bind(&FileBrowserPrivateValidatePathNameLengthFunction::
546                      OnFilePathLimitRetrieved,
547                  this, params->name.size()));
548   return true;
549 }
550
551 void FileBrowserPrivateValidatePathNameLengthFunction::OnFilePathLimitRetrieved(
552     size_t current_length,
553     size_t max_length) {
554   SetResult(new base::FundamentalValue(current_length <= max_length));
555   SendResponse(true);
556 }
557
558 bool FileBrowserPrivateFormatDeviceFunction::RunImpl() {
559   using extensions::api::file_browser_private::FormatDevice::Params;
560   const scoped_ptr<Params> params(Params::Create(*args_));
561   EXTENSION_FUNCTION_VALIDATE(params);
562
563   base::FilePath file_path = file_manager::util::GetLocalPathFromURL(
564       render_view_host(), GetProfile(), GURL(params->mount_path));
565   if (file_path.empty())
566     return false;
567
568   DiskMountManager::GetInstance()->FormatMountedDevice(file_path.value());
569   SendResponse(true);
570   return true;
571 }
572
573 bool FileBrowserPrivateStartCopyFunction::RunImpl() {
574   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
575
576   using  extensions::api::file_browser_private::StartCopy::Params;
577   const scoped_ptr<Params> params(Params::Create(*args_));
578   EXTENSION_FUNCTION_VALIDATE(params);
579
580   if (params->source_url.empty() || params->parent.empty() ||
581       params->new_name.empty()) {
582     error_ = base::IntToString(fileapi::PlatformFileErrorToWebFileError(
583         base::PLATFORM_FILE_ERROR_INVALID_URL));
584     return false;
585   }
586
587   scoped_refptr<fileapi::FileSystemContext> file_system_context =
588       file_manager::util::GetFileSystemContextForRenderViewHost(
589           GetProfile(), render_view_host());
590
591   fileapi::FileSystemURL source_url(
592       file_system_context->CrackURL(GURL(params->source_url)));
593   fileapi::FileSystemURL destination_url(file_system_context->CrackURL(
594       GURL(params->parent + "/" + params->new_name)));
595
596   if (!source_url.is_valid() || !destination_url.is_valid()) {
597     error_ = base::IntToString(fileapi::PlatformFileErrorToWebFileError(
598         base::PLATFORM_FILE_ERROR_INVALID_URL));
599     return false;
600   }
601
602   return BrowserThread::PostTaskAndReplyWithResult(
603       BrowserThread::IO,
604       FROM_HERE,
605       base::Bind(&StartCopyOnIOThread,
606                  GetProfile(),
607                  file_system_context,
608                  source_url,
609                  destination_url),
610       base::Bind(&FileBrowserPrivateStartCopyFunction::RunAfterStartCopy,
611                  this));
612 }
613
614 void FileBrowserPrivateStartCopyFunction::RunAfterStartCopy(
615     int operation_id) {
616   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
617
618   SetResult(Value::CreateIntegerValue(operation_id));
619   SendResponse(true);
620 }
621
622 bool FileBrowserPrivateCancelCopyFunction::RunImpl() {
623   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
624
625   using  extensions::api::file_browser_private::CancelCopy::Params;
626   const scoped_ptr<Params> params(Params::Create(*args_));
627   EXTENSION_FUNCTION_VALIDATE(params);
628
629   scoped_refptr<fileapi::FileSystemContext> file_system_context =
630       file_manager::util::GetFileSystemContextForRenderViewHost(
631           GetProfile(), render_view_host());
632
633   // We don't much take care about the result of cancellation.
634   BrowserThread::PostTask(
635       BrowserThread::IO,
636       FROM_HERE,
637       base::Bind(&CancelCopyOnIOThread, file_system_context, params->copy_id));
638   SendResponse(true);
639   return true;
640 }
641
642 }  // namespace extensions