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