Upstream version 11.40.277.0
[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
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 "content/public/common/url_constants.h"
33 #include "net/base/escape.h"
34 #include "storage/browser/fileapi/file_system_context.h"
35 #include "storage/browser/fileapi/file_system_file_util.h"
36 #include "storage/browser/fileapi/file_system_operation_context.h"
37 #include "storage/browser/fileapi/file_system_operation_runner.h"
38 #include "storage/browser/fileapi/file_system_url.h"
39 #include "storage/common/fileapi/file_system_info.h"
40 #include "storage/common/fileapi/file_system_types.h"
41 #include "storage/common/fileapi/file_system_util.h"
42
43 using chromeos::disks::DiskMountManager;
44 using content::BrowserThread;
45 using content::ChildProcessSecurityPolicy;
46 using file_manager::util::EntryDefinition;
47 using file_manager::util::FileDefinition;
48 using storage::FileSystemURL;
49
50 namespace extensions {
51 namespace {
52
53 // Retrieves total and remaining available size on |mount_path|.
54 void GetSizeStatsOnBlockingPool(const std::string& mount_path,
55                                 uint64* total_size,
56                                 uint64* remaining_size) {
57   struct statvfs stat = {};  // Zero-clear
58   if (HANDLE_EINTR(statvfs(mount_path.c_str(), &stat)) == 0) {
59     *total_size = static_cast<uint64>(stat.f_blocks) * stat.f_frsize;
60     *remaining_size = static_cast<uint64>(stat.f_bavail) * stat.f_frsize;
61   }
62 }
63
64 // Retrieves the maximum file name length of the file system of |path|.
65 // Returns 0 if it could not be queried.
66 size_t GetFileNameMaxLengthOnBlockingPool(const std::string& path) {
67   struct statvfs stat = {};
68   if (HANDLE_EINTR(statvfs(path.c_str(), &stat)) != 0) {
69     // The filesystem seems not supporting statvfs(). Assume it to be a commonly
70     // used bound 255, and log the failure.
71     LOG(ERROR) << "Cannot statvfs() the name length limit for: " << path;
72     return 255;
73   }
74   return stat.f_namemax;
75 }
76
77 // Returns EventRouter for the |profile_id| if available.
78 file_manager::EventRouter* GetEventRouterByProfileId(void* profile_id) {
79   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
80
81   // |profile_id| needs to be checked with ProfileManager::IsValidProfile
82   // before using it.
83   Profile* profile = reinterpret_cast<Profile*>(profile_id);
84   if (!g_browser_process->profile_manager()->IsValidProfile(profile))
85     return NULL;
86
87   return file_manager::EventRouterFactory::GetForProfile(profile);
88 }
89
90 // Notifies the copy progress to extensions via event router.
91 void NotifyCopyProgress(
92     void* profile_id,
93     storage::FileSystemOperationRunner::OperationID operation_id,
94     storage::FileSystemOperation::CopyProgressType type,
95     const FileSystemURL& source_url,
96     const FileSystemURL& destination_url,
97     int64 size) {
98   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
99
100   file_manager::EventRouter* event_router =
101       GetEventRouterByProfileId(profile_id);
102   if (event_router) {
103     event_router->OnCopyProgress(
104         operation_id, type,
105         source_url.ToGURL(), destination_url.ToGURL(), size);
106   }
107 }
108
109 // Callback invoked periodically on progress update of Copy().
110 void OnCopyProgress(
111     void* profile_id,
112     storage::FileSystemOperationRunner::OperationID* operation_id,
113     storage::FileSystemOperation::CopyProgressType type,
114     const FileSystemURL& source_url,
115     const FileSystemURL& destination_url,
116     int64 size) {
117   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
118
119   BrowserThread::PostTask(
120       BrowserThread::UI, FROM_HERE,
121       base::Bind(&NotifyCopyProgress,
122                  profile_id, *operation_id, type,
123                  source_url, destination_url, size));
124 }
125
126 // Notifies the copy completion to extensions via event router.
127 void NotifyCopyCompletion(
128     void* profile_id,
129     storage::FileSystemOperationRunner::OperationID operation_id,
130     const FileSystemURL& source_url,
131     const FileSystemURL& destination_url,
132     base::File::Error error) {
133   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
134
135   file_manager::EventRouter* event_router =
136       GetEventRouterByProfileId(profile_id);
137   if (event_router)
138     event_router->OnCopyCompleted(
139         operation_id,
140         source_url.ToGURL(), destination_url.ToGURL(), error);
141 }
142
143 // Callback invoked upon completion of Copy() (regardless of succeeded or
144 // failed).
145 void OnCopyCompleted(
146     void* profile_id,
147     storage::FileSystemOperationRunner::OperationID* operation_id,
148     const FileSystemURL& source_url,
149     const FileSystemURL& destination_url,
150     base::File::Error error) {
151   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
152
153   BrowserThread::PostTask(
154       BrowserThread::UI, FROM_HERE,
155       base::Bind(&NotifyCopyCompletion,
156                  profile_id, *operation_id,
157                  source_url, destination_url, error));
158 }
159
160 // Starts the copy operation via FileSystemOperationRunner.
161 storage::FileSystemOperationRunner::OperationID StartCopyOnIOThread(
162     void* profile_id,
163     scoped_refptr<storage::FileSystemContext> file_system_context,
164     const FileSystemURL& source_url,
165     const FileSystemURL& destination_url) {
166   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
167
168   // Note: |operation_id| is owned by the callback for
169   // FileSystemOperationRunner::Copy(). It is always called in the next message
170   // loop or later, so at least during this invocation it should alive.
171   storage::FileSystemOperationRunner::OperationID* operation_id =
172       new storage::FileSystemOperationRunner::OperationID;
173   *operation_id = file_system_context->operation_runner()->Copy(
174       source_url,
175       destination_url,
176       storage::FileSystemOperation::OPTION_PRESERVE_LAST_MODIFIED,
177       base::Bind(&OnCopyProgress, profile_id, base::Unretained(operation_id)),
178       base::Bind(&OnCopyCompleted,
179                  profile_id,
180                  base::Owned(operation_id),
181                  source_url,
182                  destination_url));
183   return *operation_id;
184 }
185
186 void OnCopyCancelled(base::File::Error error) {
187   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
188
189   // We just ignore the status if the copy is actually cancelled or not,
190   // because failing cancellation means the operation is not running now.
191   DLOG_IF(WARNING, error != base::File::FILE_OK)
192       << "Failed to cancel copy: " << error;
193 }
194
195 // Cancels the running copy operation identified by |operation_id|.
196 void CancelCopyOnIOThread(
197     scoped_refptr<storage::FileSystemContext> file_system_context,
198     storage::FileSystemOperationRunner::OperationID operation_id) {
199   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
200
201   file_system_context->operation_runner()->Cancel(
202       operation_id, base::Bind(&OnCopyCancelled));
203 }
204
205 // Converts a status code to a bool value and calls the |callback| with it.
206 void StatusCallbackToResponseCallback(
207     const base::Callback<void(bool)>& callback,
208     base::File::Error result) {
209   callback.Run(result == base::File::FILE_OK);
210 }
211
212 }  // namespace
213
214 void FileManagerPrivateRequestFileSystemFunction::DidFail(
215     base::File::Error error_code) {
216   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
217
218   SetError(base::StringPrintf("File error %d", static_cast<int>(error_code)));
219   SendResponse(false);
220 }
221
222 bool
223 FileManagerPrivateRequestFileSystemFunction::SetupFileSystemAccessPermissions(
224     scoped_refptr<storage::FileSystemContext> file_system_context,
225     int child_id,
226     Profile* profile,
227     scoped_refptr<const extensions::Extension> extension) {
228   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
229
230   if (!extension.get())
231     return false;
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   // Grant permission to request externalfile scheme. The permission is needed
263   // to start drag for external file URL.
264   ChildProcessSecurityPolicy::GetInstance()->GrantScheme(
265       child_id, content::kExternalFileScheme);
266
267   return true;
268 }
269
270 bool FileManagerPrivateRequestFileSystemFunction::RunAsync() {
271   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
272   using extensions::api::file_manager_private::RequestFileSystem::Params;
273   const scoped_ptr<Params> params(Params::Create(*args_));
274   EXTENSION_FUNCTION_VALIDATE(params);
275
276   if (!dispatcher() || !render_view_host() || !render_view_host()->GetProcess())
277     return false;
278
279   set_log_on_completion(true);
280
281   using file_manager::VolumeManager;
282   using file_manager::VolumeInfo;
283   VolumeManager* const volume_manager = VolumeManager::Get(GetProfile());
284   if (!volume_manager)
285     return false;
286
287   VolumeInfo volume_info;
288   if (!volume_manager->FindVolumeInfoById(params->volume_id, &volume_info)) {
289     DidFail(base::File::FILE_ERROR_NOT_FOUND);
290     return false;
291   }
292
293   scoped_refptr<storage::FileSystemContext> file_system_context =
294       file_manager::util::GetFileSystemContextForRenderViewHost(
295           GetProfile(), render_view_host());
296
297   // Set up file permission access.
298   const int child_id = render_view_host()->GetProcess()->GetID();
299   if (!SetupFileSystemAccessPermissions(
300           file_system_context, child_id, GetProfile(), extension())) {
301     DidFail(base::File::FILE_ERROR_SECURITY);
302     return false;
303   }
304
305   FileDefinition file_definition;
306   if (!file_manager::util::ConvertAbsoluteFilePathToRelativeFileSystemPath(
307            GetProfile(),
308            extension_id(),
309            volume_info.mount_path,
310            &file_definition.virtual_path)) {
311     DidFail(base::File::FILE_ERROR_INVALID_OPERATION);
312     return false;
313   }
314   file_definition.is_directory = true;
315
316   file_manager::util::ConvertFileDefinitionToEntryDefinition(
317       GetProfile(),
318       extension_id(),
319       file_definition,
320       base::Bind(
321           &FileManagerPrivateRequestFileSystemFunction::OnEntryDefinition,
322           this));
323   return true;
324 }
325
326 void FileManagerPrivateRequestFileSystemFunction::OnEntryDefinition(
327     const EntryDefinition& entry_definition) {
328   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
329
330   if (entry_definition.error != base::File::FILE_OK) {
331     DidFail(entry_definition.error);
332     return;
333   }
334
335   if (!entry_definition.is_directory) {
336     DidFail(base::File::FILE_ERROR_NOT_A_DIRECTORY);
337     return;
338   }
339
340   base::DictionaryValue* dict = new base::DictionaryValue();
341   SetResult(dict);
342   dict->SetString("name", entry_definition.file_system_name);
343   dict->SetString("root_url", entry_definition.file_system_root_url);
344   dict->SetInteger("error", drive::FILE_ERROR_OK);
345   SendResponse(true);
346 }
347
348 void FileWatchFunctionBase::Respond(bool success) {
349   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
350
351   SetResult(new base::FundamentalValue(success));
352   SendResponse(success);
353 }
354
355 bool FileWatchFunctionBase::RunAsync() {
356   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
357
358   if (!render_view_host() || !render_view_host()->GetProcess())
359     return false;
360
361   // First param is url of a file to watch.
362   std::string url;
363   if (!args_->GetString(0, &url) || url.empty())
364     return false;
365
366   scoped_refptr<storage::FileSystemContext> file_system_context =
367       file_manager::util::GetFileSystemContextForRenderViewHost(
368           GetProfile(), render_view_host());
369
370   const FileSystemURL file_system_url =
371       file_system_context->CrackURL(GURL(url));
372   if (file_system_url.path().empty()) {
373     Respond(false);
374     return true;
375   }
376
377   PerformFileWatchOperation(file_system_context, file_system_url,
378                             extension_id());
379   return true;
380 }
381
382 void FileManagerPrivateAddFileWatchFunction::PerformFileWatchOperation(
383     scoped_refptr<storage::FileSystemContext> file_system_context,
384     const storage::FileSystemURL& file_system_url,
385     const std::string& extension_id) {
386   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
387
388   file_manager::EventRouter* const event_router =
389       file_manager::EventRouterFactory::GetForProfile(GetProfile());
390
391   storage::WatcherManager* const watcher_manager =
392       file_system_context->GetWatcherManager(file_system_url.type());
393   if (watcher_manager) {
394     watcher_manager->AddWatcher(
395         file_system_url, false /* recursive */,
396         base::Bind(
397             &StatusCallbackToResponseCallback,
398             base::Bind(&FileManagerPrivateAddFileWatchFunction::Respond, this)),
399         base::Bind(&file_manager::EventRouter::OnWatcherManagerNotification,
400                    event_router->GetWeakPtr(), file_system_url, extension_id));
401     return;
402   }
403
404   // Obsolete. Fallback code if storage::WatcherManager is not implemented.
405   event_router->AddFileWatch(
406       file_system_url.path(), file_system_url.virtual_path(), extension_id,
407       base::Bind(&FileManagerPrivateAddFileWatchFunction::Respond, this));
408 }
409
410 void FileManagerPrivateRemoveFileWatchFunction::PerformFileWatchOperation(
411     scoped_refptr<storage::FileSystemContext> file_system_context,
412     const storage::FileSystemURL& file_system_url,
413     const std::string& extension_id) {
414   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
415
416   file_manager::EventRouter* const event_router =
417       file_manager::EventRouterFactory::GetForProfile(GetProfile());
418
419   storage::WatcherManager* const watcher_manager =
420       file_system_context->GetWatcherManager(file_system_url.type());
421   if (watcher_manager) {
422     watcher_manager->RemoveWatcher(
423         file_system_url, false /* recursive */,
424         base::Bind(&StatusCallbackToResponseCallback,
425                    base::Bind(&FileWatchFunctionBase::Respond, this)));
426     return;
427   }
428
429   // Obsolete. Fallback code if storage::WatcherManager is not implemented.
430   event_router->RemoveFileWatch(file_system_url.path(), extension_id);
431   Respond(true);
432 }
433
434 bool FileManagerPrivateGetSizeStatsFunction::RunAsync() {
435   using extensions::api::file_manager_private::GetSizeStats::Params;
436   const scoped_ptr<Params> params(Params::Create(*args_));
437   EXTENSION_FUNCTION_VALIDATE(params);
438
439   using file_manager::VolumeManager;
440   using file_manager::VolumeInfo;
441   VolumeManager* volume_manager = VolumeManager::Get(GetProfile());
442   if (!volume_manager)
443     return false;
444
445   VolumeInfo volume_info;
446   if (!volume_manager->FindVolumeInfoById(params->volume_id, &volume_info))
447     return false;
448
449   if (volume_info.type == file_manager::VOLUME_TYPE_GOOGLE_DRIVE) {
450     drive::FileSystemInterface* file_system =
451         drive::util::GetFileSystemByProfile(GetProfile());
452     if (!file_system) {
453       // |file_system| is NULL if Drive is disabled.
454       // If stats couldn't be gotten for drive, result should be left
455       // undefined. See comments in GetDriveAvailableSpaceCallback().
456       SendResponse(true);
457       return true;
458     }
459
460     file_system->GetAvailableSpace(
461         base::Bind(&FileManagerPrivateGetSizeStatsFunction::
462                        GetDriveAvailableSpaceCallback,
463                    this));
464   } else {
465     uint64* total_size = new uint64(0);
466     uint64* remaining_size = new uint64(0);
467     BrowserThread::PostBlockingPoolTaskAndReply(
468         FROM_HERE,
469         base::Bind(&GetSizeStatsOnBlockingPool,
470                    volume_info.mount_path.value(),
471                    total_size,
472                    remaining_size),
473         base::Bind(&FileManagerPrivateGetSizeStatsFunction::
474                        GetSizeStatsCallback,
475                    this,
476                    base::Owned(total_size),
477                    base::Owned(remaining_size)));
478   }
479   return true;
480 }
481
482 void FileManagerPrivateGetSizeStatsFunction::GetDriveAvailableSpaceCallback(
483     drive::FileError error,
484     int64 bytes_total,
485     int64 bytes_used) {
486   if (error == drive::FILE_ERROR_OK) {
487     const uint64 bytes_total_unsigned = bytes_total;
488     const uint64 bytes_remaining_unsigned = bytes_total - bytes_used;
489     GetSizeStatsCallback(&bytes_total_unsigned,
490                          &bytes_remaining_unsigned);
491   } else {
492     // If stats couldn't be gotten for drive, result should be left undefined.
493     SendResponse(true);
494   }
495 }
496
497 void FileManagerPrivateGetSizeStatsFunction::GetSizeStatsCallback(
498     const uint64* total_size,
499     const uint64* remaining_size) {
500   base::DictionaryValue* sizes = new base::DictionaryValue();
501   SetResult(sizes);
502
503   sizes->SetDouble("totalSize", static_cast<double>(*total_size));
504   sizes->SetDouble("remainingSize", static_cast<double>(*remaining_size));
505
506   SendResponse(true);
507 }
508
509 bool FileManagerPrivateValidatePathNameLengthFunction::RunAsync() {
510   using extensions::api::file_manager_private::ValidatePathNameLength::Params;
511   const scoped_ptr<Params> params(Params::Create(*args_));
512   EXTENSION_FUNCTION_VALIDATE(params);
513
514   scoped_refptr<storage::FileSystemContext> file_system_context =
515       file_manager::util::GetFileSystemContextForRenderViewHost(
516           GetProfile(), render_view_host());
517
518   storage::FileSystemURL filesystem_url(
519       file_system_context->CrackURL(GURL(params->parent_directory_url)));
520   if (!chromeos::FileSystemBackend::CanHandleURL(filesystem_url))
521     return false;
522
523   // No explicit limit on the length of Drive file names.
524   if (filesystem_url.type() == storage::kFileSystemTypeDrive) {
525     SetResult(new base::FundamentalValue(true));
526     SendResponse(true);
527     return true;
528   }
529
530   base::PostTaskAndReplyWithResult(
531       BrowserThread::GetBlockingPool(),
532       FROM_HERE,
533       base::Bind(&GetFileNameMaxLengthOnBlockingPool,
534                  filesystem_url.path().AsUTF8Unsafe()),
535       base::Bind(&FileManagerPrivateValidatePathNameLengthFunction::
536                      OnFilePathLimitRetrieved,
537                  this, params->name.size()));
538   return true;
539 }
540
541 void FileManagerPrivateValidatePathNameLengthFunction::OnFilePathLimitRetrieved(
542     size_t current_length,
543     size_t max_length) {
544   SetResult(new base::FundamentalValue(current_length <= max_length));
545   SendResponse(true);
546 }
547
548 bool FileManagerPrivateFormatVolumeFunction::RunAsync() {
549   using extensions::api::file_manager_private::FormatVolume::Params;
550   const scoped_ptr<Params> params(Params::Create(*args_));
551   EXTENSION_FUNCTION_VALIDATE(params);
552
553   using file_manager::VolumeManager;
554   using file_manager::VolumeInfo;
555   VolumeManager* volume_manager = VolumeManager::Get(GetProfile());
556   if (!volume_manager)
557     return false;
558
559   VolumeInfo volume_info;
560   if (!volume_manager->FindVolumeInfoById(params->volume_id, &volume_info))
561     return false;
562
563   DiskMountManager::GetInstance()->FormatMountedDevice(
564       volume_info.mount_path.AsUTF8Unsafe());
565   SendResponse(true);
566   return true;
567 }
568
569 bool FileManagerPrivateStartCopyFunction::RunAsync() {
570   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
571
572   using  extensions::api::file_manager_private::StartCopy::Params;
573   const scoped_ptr<Params> params(Params::Create(*args_));
574   EXTENSION_FUNCTION_VALIDATE(params);
575
576   if (params->source_url.empty() || params->parent.empty() ||
577       params->new_name.empty()) {
578     // Error code in format of DOMError.name.
579     SetError("EncodingError");
580     return false;
581   }
582
583   scoped_refptr<storage::FileSystemContext> file_system_context =
584       file_manager::util::GetFileSystemContextForRenderViewHost(
585           GetProfile(), render_view_host());
586
587   // |parent| may have a trailing slash if it is a root directory.
588   std::string destination_url_string = params->parent;
589   if (destination_url_string[destination_url_string.size() - 1] != '/')
590     destination_url_string += '/';
591   destination_url_string += net::EscapePath(params->new_name);
592
593   storage::FileSystemURL source_url(
594       file_system_context->CrackURL(GURL(params->source_url)));
595   storage::FileSystemURL destination_url(
596       file_system_context->CrackURL(GURL(destination_url_string)));
597
598   if (!source_url.is_valid() || !destination_url.is_valid()) {
599     // Error code in format of DOMError.name.
600     SetError("EncodingError");
601     return false;
602   }
603
604   return BrowserThread::PostTaskAndReplyWithResult(
605       BrowserThread::IO,
606       FROM_HERE,
607       base::Bind(&StartCopyOnIOThread,
608                  GetProfile(),
609                  file_system_context,
610                  source_url,
611                  destination_url),
612       base::Bind(&FileManagerPrivateStartCopyFunction::RunAfterStartCopy,
613                  this));
614 }
615
616 void FileManagerPrivateStartCopyFunction::RunAfterStartCopy(
617     int operation_id) {
618   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
619
620   SetResult(new base::FundamentalValue(operation_id));
621   SendResponse(true);
622 }
623
624 bool FileManagerPrivateCancelCopyFunction::RunAsync() {
625   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
626
627   using extensions::api::file_manager_private::CancelCopy::Params;
628   const scoped_ptr<Params> params(Params::Create(*args_));
629   EXTENSION_FUNCTION_VALIDATE(params);
630
631   scoped_refptr<storage::FileSystemContext> file_system_context =
632       file_manager::util::GetFileSystemContextForRenderViewHost(
633           GetProfile(), render_view_host());
634
635   // We don't much take care about the result of cancellation.
636   BrowserThread::PostTask(
637       BrowserThread::IO,
638       FROM_HERE,
639       base::Bind(&CancelCopyOnIOThread, file_system_context, params->copy_id));
640   SendResponse(true);
641   return true;
642 }
643
644 bool FileManagerPrivateInternalResolveIsolatedEntriesFunction::RunAsync() {
645   using extensions::api::file_manager_private_internal::ResolveIsolatedEntries::
646       Params;
647   const scoped_ptr<Params> params(Params::Create(*args_));
648   EXTENSION_FUNCTION_VALIDATE(params);
649
650   scoped_refptr<storage::FileSystemContext> file_system_context =
651       file_manager::util::GetFileSystemContextForRenderViewHost(
652           GetProfile(), render_view_host());
653   DCHECK(file_system_context.get());
654
655   const storage::ExternalFileSystemBackend* external_backend =
656       file_system_context->external_backend();
657   DCHECK(external_backend);
658
659   file_manager::util::FileDefinitionList file_definition_list;
660   for (size_t i = 0; i < params->urls.size(); ++i) {
661     FileSystemURL fileSystemUrl =
662         file_system_context->CrackURL(GURL(params->urls[i]));
663     DCHECK(external_backend->CanHandleType(fileSystemUrl.type()));
664
665     FileDefinition file_definition;
666     const bool result =
667         file_manager::util::ConvertAbsoluteFilePathToRelativeFileSystemPath(
668             GetProfile(),
669             extension_->id(),
670             fileSystemUrl.path(),
671             &file_definition.virtual_path);
672     if (!result)
673       continue;
674     // The API only supports isolated files.
675     file_definition.is_directory = false;
676     file_definition_list.push_back(file_definition);
677   }
678
679   file_manager::util::ConvertFileDefinitionListToEntryDefinitionList(
680       GetProfile(),
681       extension_->id(),
682       file_definition_list,  // Safe, since copied internally.
683       base::Bind(
684           &FileManagerPrivateInternalResolveIsolatedEntriesFunction::
685               RunAsyncAfterConvertFileDefinitionListToEntryDefinitionList,
686           this));
687   return true;
688 }
689
690 void FileManagerPrivateInternalResolveIsolatedEntriesFunction::
691     RunAsyncAfterConvertFileDefinitionListToEntryDefinitionList(scoped_ptr<
692         file_manager::util::EntryDefinitionList> entry_definition_list) {
693   using extensions::api::file_manager_private_internal::EntryDescription;
694   std::vector<linked_ptr<EntryDescription> > entries;
695
696   for (size_t i = 0; i < entry_definition_list->size(); ++i) {
697     if (entry_definition_list->at(i).error != base::File::FILE_OK)
698       continue;
699     linked_ptr<EntryDescription> entry(new EntryDescription);
700     entry->file_system_name = entry_definition_list->at(i).file_system_name;
701     entry->file_system_root = entry_definition_list->at(i).file_system_root_url;
702     entry->file_full_path =
703         "/" + entry_definition_list->at(i).full_path.AsUTF8Unsafe();
704     entry->file_is_directory = entry_definition_list->at(i).is_directory;
705     entries.push_back(entry);
706   }
707
708   results_ = extensions::api::file_manager_private_internal::
709       ResolveIsolatedEntries::Results::Create(entries);
710   SendResponse(true);
711 }
712 }  // namespace extensions