private_api_file_system.cc revision d0247b1b59f9c528cb6df88b4f2b9afaf80d181e
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/stat.h>
8#include <sys/statvfs.h>
9#include <sys/types.h>
10#include <utime.h>
11
12#include "base/path_service.h"
13#include "base/posix/eintr_wrapper.h"
14#include "base/strings/string_number_conversions.h"
15#include "base/strings/stringprintf.h"
16#include "base/task_runner_util.h"
17#include "base/threading/sequenced_worker_pool.h"
18#include "chrome/browser/browser_process.h"
19#include "chrome/browser/chromeos/drive/drive.pb.h"
20#include "chrome/browser/chromeos/drive/file_system_interface.h"
21#include "chrome/browser/chromeos/drive/file_system_util.h"
22#include "chrome/browser/chromeos/extensions/file_manager/event_router.h"
23#include "chrome/browser/chromeos/extensions/file_manager/file_browser_private_api.h"
24#include "chrome/browser/chromeos/extensions/file_manager/private_api_util.h"
25#include "chrome/browser/chromeos/file_manager/fileapi_util.h"
26#include "chrome/browser/chromeos/fileapi/file_system_backend.h"
27#include "chrome/browser/profiles/profile.h"
28#include "chrome/browser/profiles/profile_manager.h"
29#include "chrome/common/extensions/api/file_browser_private.h"
30#include "chromeos/disks/disk_mount_manager.h"
31#include "content/public/browser/browser_context.h"
32#include "content/public/browser/child_process_security_policy.h"
33#include "content/public/browser/render_process_host.h"
34#include "content/public/browser/render_view_host.h"
35#include "content/public/browser/storage_partition.h"
36#include "webkit/browser/fileapi/file_system_context.h"
37#include "webkit/browser/fileapi/file_system_file_util.h"
38#include "webkit/browser/fileapi/file_system_operation_context.h"
39#include "webkit/browser/fileapi/file_system_operation_runner.h"
40#include "webkit/browser/fileapi/file_system_url.h"
41#include "webkit/common/fileapi/file_system_types.h"
42#include "webkit/common/fileapi/file_system_util.h"
43
44using chromeos::disks::DiskMountManager;
45using content::BrowserContext;
46using content::BrowserThread;
47using content::ChildProcessSecurityPolicy;
48using content::WebContents;
49using fileapi::FileSystemURL;
50
51namespace extensions {
52namespace {
53
54// Error messages.
55const char kFileError[] = "File error %d";
56
57const 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
71base::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
105base::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).
115void 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|.
142void 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.
156size_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// Sets last modified date.
168bool SetLastModifiedOnBlockingPool(const base::FilePath& local_path,
169                                   time_t timestamp) {
170  if (local_path.empty())
171    return false;
172
173  struct stat stat_buffer;
174  if (stat(local_path.value().c_str(), &stat_buffer) != 0)
175    return false;
176
177  struct utimbuf times;
178  times.actime = stat_buffer.st_atime;
179  times.modtime = timestamp;
180  return utime(local_path.value().c_str(), &times) == 0;
181}
182
183// Returns EventRouter for the |profile_id| if available.
184file_manager::EventRouter* GetEventRouterByProfileId(void* profile_id) {
185  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
186
187  // |profile_id| needs to be checked with ProfileManager::IsValidProfile
188  // before using it.
189  Profile* profile = reinterpret_cast<Profile*>(profile_id);
190  if (!g_browser_process->profile_manager()->IsValidProfile(profile))
191    return NULL;
192
193  return file_manager::FileBrowserPrivateAPI::Get(profile)->event_router();
194}
195
196// Notifies the copy progress to extensions via event router.
197void NotifyCopyProgress(
198    void* profile_id,
199    fileapi::FileSystemOperationRunner::OperationID operation_id,
200    fileapi::FileSystemOperation::CopyProgressType type,
201    const FileSystemURL& url,
202    int64 size) {
203  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
204
205  file_manager::EventRouter* event_router =
206      GetEventRouterByProfileId(profile_id);
207  if (event_router) {
208    event_router->OnCopyProgress(
209        operation_id, type, url.ToGURL(), size);
210  }
211}
212
213// Callback invoked periodically on progress update of Copy().
214void OnCopyProgress(
215    void* profile_id,
216    fileapi::FileSystemOperationRunner::OperationID* operation_id,
217    fileapi::FileSystemOperation::CopyProgressType type,
218    const FileSystemURL& url,
219    int64 size) {
220  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
221
222  BrowserThread::PostTask(
223      BrowserThread::UI, FROM_HERE,
224      base::Bind(&NotifyCopyProgress,
225                 profile_id, *operation_id, type, url, size));
226}
227
228// Notifies the copy completion to extensions via event router.
229void NotifyCopyCompletion(
230    void* profile_id,
231    fileapi::FileSystemOperationRunner::OperationID operation_id,
232    const FileSystemURL& dest_url,
233    base::PlatformFileError error) {
234  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
235
236  file_manager::EventRouter* event_router =
237      GetEventRouterByProfileId(profile_id);
238  if (event_router)
239    event_router->OnCopyCompleted(operation_id, dest_url.ToGURL(), error);
240}
241
242// Callback invoked upon completion of Copy() (regardless of succeeded or
243// failed).
244void OnCopyCompleted(
245    void* profile_id,
246    fileapi::FileSystemOperationRunner::OperationID* operation_id,
247    const FileSystemURL& dest_url,
248    base::PlatformFileError error) {
249  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
250
251  BrowserThread::PostTask(
252      BrowserThread::UI, FROM_HERE,
253      base::Bind(&NotifyCopyCompletion,
254                 profile_id, *operation_id, dest_url, error));
255}
256
257// Starts the copy operation via FileSystemOperationRunner.
258fileapi::FileSystemOperationRunner::OperationID StartCopyOnIOThread(
259    void* profile_id,
260    scoped_refptr<fileapi::FileSystemContext> file_system_context,
261    const FileSystemURL& source_url,
262    const FileSystemURL& dest_url) {
263  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
264
265  // Note: |operation_id| is owned by the callback for
266  // FileSystemOperationRunner::Copy(). It is always called in the next message
267  // loop or later, so at least during this invocation it should alive.
268  fileapi::FileSystemOperationRunner::OperationID* operation_id =
269      new fileapi::FileSystemOperationRunner::OperationID;
270  *operation_id = file_system_context->operation_runner()->Copy(
271      source_url, dest_url,
272      base::Bind(&OnCopyProgress,
273                 profile_id, base::Unretained(operation_id)),
274      base::Bind(&OnCopyCompleted,
275                 profile_id, base::Owned(operation_id), dest_url));
276  return *operation_id;
277}
278
279void OnCopyCancelled(base::PlatformFileError error) {
280  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
281
282  // We just ignore the status if the copy is actually cancelled or not,
283  // because failing cancellation means the operation is not running now.
284  DLOG_IF(WARNING, error != base::PLATFORM_FILE_OK)
285      << "Failed to cancel copy: " << error;
286}
287
288// Cancels the running copy operation identified by |operation_id|.
289void CancelCopyOnIOThread(
290    scoped_refptr<fileapi::FileSystemContext> file_system_context,
291    fileapi::FileSystemOperationRunner::OperationID operation_id) {
292  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
293
294  file_system_context->operation_runner()->Cancel(
295      operation_id, base::Bind(&OnCopyCancelled));
296}
297
298}  // namespace
299
300void FileBrowserPrivateRequestFileSystemFunction::DidOpenFileSystem(
301    scoped_refptr<fileapi::FileSystemContext> file_system_context,
302    base::PlatformFileError result,
303    const std::string& name,
304    const GURL& root_url) {
305  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
306
307  if (result != base::PLATFORM_FILE_OK) {
308    DidFail(result);
309    return;
310  }
311
312  // RenderViewHost may have gone while the task is posted asynchronously.
313  if (!render_view_host()) {
314    DidFail(base::PLATFORM_FILE_ERROR_FAILED);
315    return;
316  }
317
318  // Set up file permission access.
319  const int child_id = render_view_host()->GetProcess()->GetID();
320  if (!SetupFileSystemAccessPermissions(file_system_context,
321                                        child_id,
322                                        GetExtension())) {
323    DidFail(base::PLATFORM_FILE_ERROR_SECURITY);
324    return;
325  }
326
327  // Set permissions for the Drive mount point immediately when we kick of
328  // first instance of file manager. The actual mount event will be sent to
329  // UI only when we perform proper authentication.
330  //
331  // Note that we call this function even when Drive is disabled by the
332  // setting. Otherwise, we need to call this when the setting is changed at
333  // a later time, which complicates the code.
334  SetDriveMountPointPermissions(profile_, extension_id(), render_view_host());
335
336  DictionaryValue* dict = new DictionaryValue();
337  SetResult(dict);
338  dict->SetString("name", name);
339  dict->SetString("root_url", root_url.spec());
340  dict->SetInteger("error", drive::FILE_ERROR_OK);
341  SendResponse(true);
342}
343
344void FileBrowserPrivateRequestFileSystemFunction::DidFail(
345    base::PlatformFileError error_code) {
346  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
347
348  error_ = base::StringPrintf(kFileError, static_cast<int>(error_code));
349  SendResponse(false);
350}
351
352bool FileBrowserPrivateRequestFileSystemFunction::
353    SetupFileSystemAccessPermissions(
354        scoped_refptr<fileapi::FileSystemContext> file_system_context,
355        int child_id,
356        scoped_refptr<const extensions::Extension> extension) {
357  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
358
359  if (!extension.get())
360    return false;
361
362  // Make sure that only component extension can access the entire
363  // local file system.
364  if (extension_->location() != extensions::Manifest::COMPONENT) {
365    NOTREACHED() << "Private method access by non-component extension "
366                 << extension->id();
367    return false;
368  }
369
370  fileapi::ExternalFileSystemBackend* backend =
371      file_system_context->external_backend();
372  if (!backend)
373    return false;
374
375  // Grant full access to File API from this component extension.
376  backend->GrantFullAccessToExtension(extension_->id());
377
378  // Grant R/W file permissions to the renderer hosting component
379  // extension for all paths exposed by our local file system backend.
380  std::vector<base::FilePath> root_dirs = backend->GetRootDirectories();
381  for (size_t i = 0; i < root_dirs.size(); ++i) {
382    ChildProcessSecurityPolicy::GetInstance()->GrantCreateReadWriteFile(
383        child_id, root_dirs[i]);
384  }
385  return true;
386}
387
388bool FileBrowserPrivateRequestFileSystemFunction::RunImpl() {
389  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
390  using extensions::api::file_browser_private::RequestFileSystem::Params;
391  const scoped_ptr<Params> params(Params::Create(*args_));
392  EXTENSION_FUNCTION_VALIDATE(params);
393
394  // TODO(satorux): Handle the file system ID. crbug.com/284963.
395  DCHECK_EQ("compatible", params->file_system_id);
396
397  if (!dispatcher() || !render_view_host() || !render_view_host()->GetProcess())
398    return false;
399
400  set_log_on_completion(true);
401
402  scoped_refptr<fileapi::FileSystemContext> file_system_context =
403      file_manager::util::GetFileSystemContextForRenderViewHost(
404          profile(), render_view_host());
405
406  const GURL origin_url = source_url_.GetOrigin();
407  file_system_context->OpenFileSystem(
408      origin_url,
409      fileapi::kFileSystemTypeExternal,
410      fileapi::OPEN_FILE_SYSTEM_FAIL_IF_NONEXISTENT,
411      base::Bind(&FileBrowserPrivateRequestFileSystemFunction::
412                     DidOpenFileSystem,
413                 this,
414                 file_system_context));
415  return true;
416}
417
418void FileWatchFunctionBase::Respond(bool success) {
419  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
420
421  SetResult(Value::CreateBooleanValue(success));
422  SendResponse(success);
423}
424
425bool FileWatchFunctionBase::RunImpl() {
426  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
427
428  if (!render_view_host() || !render_view_host()->GetProcess())
429    return false;
430
431  // First param is url of a file to watch.
432  std::string url;
433  if (!args_->GetString(0, &url) || url.empty())
434    return false;
435
436  scoped_refptr<fileapi::FileSystemContext> file_system_context =
437      file_manager::util::GetFileSystemContextForRenderViewHost(
438          profile(), render_view_host());
439
440  FileSystemURL file_watch_url = file_system_context->CrackURL(GURL(url));
441  base::FilePath local_path = file_watch_url.path();
442  base::FilePath virtual_path = file_watch_url.virtual_path();
443  if (local_path.empty()) {
444    Respond(false);
445    return true;
446  }
447  PerformFileWatchOperation(local_path, virtual_path, extension_id());
448
449  return true;
450}
451
452void FileBrowserPrivateAddFileWatchFunction::PerformFileWatchOperation(
453    const base::FilePath& local_path,
454    const base::FilePath& virtual_path,
455    const std::string& extension_id) {
456  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
457
458  file_manager::EventRouter* event_router =
459      file_manager::FileBrowserPrivateAPI::Get(profile_)->event_router();
460  event_router->AddFileWatch(
461      local_path,
462      virtual_path,
463      extension_id,
464      base::Bind(&FileBrowserPrivateAddFileWatchFunction::Respond, this));
465}
466
467void FileBrowserPrivateRemoveFileWatchFunction::PerformFileWatchOperation(
468    const base::FilePath& local_path,
469    const base::FilePath& unused,
470    const std::string& extension_id) {
471  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
472
473  file_manager::EventRouter* event_router =
474      file_manager::FileBrowserPrivateAPI::Get(profile_)->event_router();
475  event_router->RemoveFileWatch(local_path, extension_id);
476  Respond(true);
477}
478
479bool FileBrowserPrivateSetLastModifiedFunction::RunImpl() {
480  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
481  using extensions::api::file_browser_private::SetLastModified::Params;
482  const scoped_ptr<Params> params(Params::Create(*args_));
483  EXTENSION_FUNCTION_VALIDATE(params);
484
485  base::FilePath local_path = file_manager::util::GetLocalPathFromURL(
486      render_view_host(), profile(), GURL(params->file_url));
487
488  base::PostTaskAndReplyWithResult(
489      BrowserThread::GetBlockingPool(),
490      FROM_HERE,
491      base::Bind(&SetLastModifiedOnBlockingPool,
492                 local_path,
493                 strtoul(params->last_modified.c_str(), NULL, 0)),
494      base::Bind(&FileBrowserPrivateSetLastModifiedFunction::SendResponse,
495                 this));
496  return true;
497}
498
499bool FileBrowserPrivateGetSizeStatsFunction::RunImpl() {
500  using extensions::api::file_browser_private::GetSizeStats::Params;
501  const scoped_ptr<Params> params(Params::Create(*args_));
502  EXTENSION_FUNCTION_VALIDATE(params);
503
504  base::FilePath file_path = file_manager::util::GetLocalPathFromURL(
505      render_view_host(), profile(), GURL(params->mount_path));
506  if (file_path.empty())
507    return false;
508
509  if (file_path == drive::util::GetDriveMountPointPath()) {
510    drive::FileSystemInterface* file_system =
511        drive::util::GetFileSystemByProfile(profile());
512    if (!file_system) {
513      // |file_system| is NULL if Drive is disabled.
514      // If stats couldn't be gotten for drive, result should be left
515      // undefined. See comments in GetDriveAvailableSpaceCallback().
516      SendResponse(true);
517      return true;
518    }
519
520    file_system->GetAvailableSpace(
521        base::Bind(&FileBrowserPrivateGetSizeStatsFunction::
522                       GetDriveAvailableSpaceCallback,
523                   this));
524  } else {
525    uint64* total_size = new uint64(0);
526    uint64* remaining_size = new uint64(0);
527    BrowserThread::PostBlockingPoolTaskAndReply(
528        FROM_HERE,
529        base::Bind(&GetSizeStatsOnBlockingPool,
530                   file_path.value(),
531                   total_size,
532                   remaining_size),
533        base::Bind(&FileBrowserPrivateGetSizeStatsFunction::
534                       GetSizeStatsCallback,
535                   this,
536                   base::Owned(total_size),
537                   base::Owned(remaining_size)));
538  }
539  return true;
540}
541
542void FileBrowserPrivateGetSizeStatsFunction::GetDriveAvailableSpaceCallback(
543    drive::FileError error,
544    int64 bytes_total,
545    int64 bytes_used) {
546  if (error == drive::FILE_ERROR_OK) {
547    const uint64 bytes_total_unsigned = bytes_total;
548    const uint64 bytes_remaining_unsigned = bytes_total - bytes_used;
549    GetSizeStatsCallback(&bytes_total_unsigned,
550                         &bytes_remaining_unsigned);
551  } else {
552    // If stats couldn't be gotten for drive, result should be left undefined.
553    SendResponse(true);
554  }
555}
556
557void FileBrowserPrivateGetSizeStatsFunction::GetSizeStatsCallback(
558    const uint64* total_size,
559    const uint64* remaining_size) {
560  base::DictionaryValue* sizes = new base::DictionaryValue();
561  SetResult(sizes);
562
563  sizes->SetDouble("totalSize", static_cast<double>(*total_size));
564  sizes->SetDouble("remainingSize", static_cast<double>(*remaining_size));
565
566  SendResponse(true);
567}
568
569bool FileBrowserPrivateGetVolumeMetadataFunction::RunImpl() {
570  using extensions::api::file_browser_private::GetVolumeMetadata::Params;
571  const scoped_ptr<Params> params(Params::Create(*args_));
572  EXTENSION_FUNCTION_VALIDATE(params);
573
574  base::FilePath file_path = file_manager::util::GetLocalPathFromURL(
575      render_view_host(), profile(), GURL(params->mount_url));
576  if (file_path.empty()) {
577    error_ = "Invalid mount path.";
578    return false;
579  }
580
581  results_.reset();
582
583  base::FilePath home_path;
584  // TODO(hidehiko): Return the volume info for Drive File System.
585  if (PathService::Get(base::DIR_HOME, &home_path) &&
586      file_path == home_path.AppendASCII("Downloads")) {
587    // Return simple (fake) volume metadata for Downloads volume.
588    SetResult(CreateDownloadsVolumeMetadata());
589  } else {
590    const DiskMountManager::Disk* volume = GetVolumeAsDisk(file_path.value());
591    if (volume)
592      SetResult(CreateValueFromDisk(profile_, extension_->id(), volume));
593  }
594
595  SendResponse(true);
596  return true;
597}
598
599bool FileBrowserPrivateValidatePathNameLengthFunction::RunImpl() {
600  using extensions::api::file_browser_private::ValidatePathNameLength::Params;
601  const scoped_ptr<Params> params(Params::Create(*args_));
602  EXTENSION_FUNCTION_VALIDATE(params);
603
604  scoped_refptr<fileapi::FileSystemContext> file_system_context =
605      file_manager::util::GetFileSystemContextForRenderViewHost(
606          profile(), render_view_host());
607
608  fileapi::FileSystemURL filesystem_url(
609      file_system_context->CrackURL(GURL(params->parent_directory_url)));
610  if (!chromeos::FileSystemBackend::CanHandleURL(filesystem_url))
611    return false;
612
613  // No explicit limit on the length of Drive file names.
614  if (filesystem_url.type() == fileapi::kFileSystemTypeDrive) {
615    SetResult(new base::FundamentalValue(true));
616    SendResponse(true);
617    return true;
618  }
619
620  base::PostTaskAndReplyWithResult(
621      BrowserThread::GetBlockingPool(),
622      FROM_HERE,
623      base::Bind(&GetFileNameMaxLengthOnBlockingPool,
624                 filesystem_url.path().AsUTF8Unsafe()),
625      base::Bind(&FileBrowserPrivateValidatePathNameLengthFunction::
626                     OnFilePathLimitRetrieved,
627                 this, params->name.size()));
628  return true;
629}
630
631void FileBrowserPrivateValidatePathNameLengthFunction::OnFilePathLimitRetrieved(
632    size_t current_length,
633    size_t max_length) {
634  SetResult(new base::FundamentalValue(current_length <= max_length));
635  SendResponse(true);
636}
637
638bool FileBrowserPrivateFormatDeviceFunction::RunImpl() {
639  using extensions::api::file_browser_private::FormatDevice::Params;
640  const scoped_ptr<Params> params(Params::Create(*args_));
641  EXTENSION_FUNCTION_VALIDATE(params);
642
643  base::FilePath file_path = file_manager::util::GetLocalPathFromURL(
644      render_view_host(), profile(), GURL(params->mount_path));
645  if (file_path.empty())
646    return false;
647
648  DiskMountManager::GetInstance()->FormatMountedDevice(file_path.value());
649  SendResponse(true);
650  return true;
651}
652
653bool FileBrowserPrivateStartCopyFunction::RunImpl() {
654  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
655
656  using  extensions::api::file_browser_private::StartCopy::Params;
657  const scoped_ptr<Params> params(Params::Create(*args_));
658  EXTENSION_FUNCTION_VALIDATE(params);
659
660  if (params->source_url.empty() || params->parent.empty() ||
661      params->new_name.empty()) {
662    error_ = base::IntToString(fileapi::PlatformFileErrorToWebFileError(
663        base::PLATFORM_FILE_ERROR_INVALID_URL));
664    return false;
665  }
666
667  scoped_refptr<fileapi::FileSystemContext> file_system_context =
668      file_manager::util::GetFileSystemContextForRenderViewHost(
669          profile(), render_view_host());
670
671  fileapi::FileSystemURL source_url(
672      file_system_context->CrackURL(GURL(params->source_url)));
673  fileapi::FileSystemURL dest_url(file_system_context->CrackURL(
674      GURL(params->parent + "/" + params->new_name)));
675
676  if (!source_url.is_valid() || !dest_url.is_valid()) {
677    error_ = base::IntToString(fileapi::PlatformFileErrorToWebFileError(
678        base::PLATFORM_FILE_ERROR_INVALID_URL));
679    return false;
680  }
681
682  return BrowserThread::PostTaskAndReplyWithResult(
683      BrowserThread::IO,
684      FROM_HERE,
685      base::Bind(&StartCopyOnIOThread,
686                 profile(), file_system_context, source_url, dest_url),
687      base::Bind(&FileBrowserPrivateStartCopyFunction::RunAfterStartCopy,
688                 this));
689}
690
691void FileBrowserPrivateStartCopyFunction::RunAfterStartCopy(
692    int operation_id) {
693  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
694
695  SetResult(Value::CreateIntegerValue(operation_id));
696  SendResponse(true);
697}
698
699bool FileBrowserPrivateCancelCopyFunction::RunImpl() {
700  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
701
702  using  extensions::api::file_browser_private::CancelCopy::Params;
703  const scoped_ptr<Params> params(Params::Create(*args_));
704  EXTENSION_FUNCTION_VALIDATE(params);
705
706  scoped_refptr<fileapi::FileSystemContext> file_system_context =
707      file_manager::util::GetFileSystemContextForRenderViewHost(
708          profile(), render_view_host());
709
710  // We don't much take care about the result of cancellation.
711  BrowserThread::PostTask(
712      BrowserThread::IO,
713      FROM_HERE,
714      base::Bind(&CancelCopyOnIOThread, file_system_context, params->copy_id));
715  SendResponse(true);
716  return true;
717}
718
719}  // namespace extensions
720