Upstream version 10.39.225.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 "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