| // Copyright 2013 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "chrome/browser/chromeos/extensions/file_manager/private_api_file_system.h" |
| |
| #include <sys/stat.h> |
| #include <sys/statvfs.h> |
| #include <sys/types.h> |
| #include <utime.h> |
| |
| #include "base/path_service.h" |
| #include "base/posix/eintr_wrapper.h" |
| #include "base/strings/string_number_conversions.h" |
| #include "base/strings/stringprintf.h" |
| #include "base/task_runner_util.h" |
| #include "base/threading/sequenced_worker_pool.h" |
| #include "chrome/browser/browser_process.h" |
| #include "chrome/browser/chromeos/drive/drive.pb.h" |
| #include "chrome/browser/chromeos/drive/file_system_interface.h" |
| #include "chrome/browser/chromeos/drive/file_system_util.h" |
| #include "chrome/browser/chromeos/extensions/file_manager/event_router.h" |
| #include "chrome/browser/chromeos/extensions/file_manager/file_browser_private_api.h" |
| #include "chrome/browser/chromeos/extensions/file_manager/private_api_util.h" |
| #include "chrome/browser/chromeos/file_manager/fileapi_util.h" |
| #include "chrome/browser/chromeos/fileapi/file_system_backend.h" |
| #include "chrome/browser/profiles/profile.h" |
| #include "chrome/browser/profiles/profile_manager.h" |
| #include "chrome/common/extensions/api/file_browser_private.h" |
| #include "chromeos/disks/disk_mount_manager.h" |
| #include "content/public/browser/browser_context.h" |
| #include "content/public/browser/child_process_security_policy.h" |
| #include "content/public/browser/render_process_host.h" |
| #include "content/public/browser/render_view_host.h" |
| #include "content/public/browser/storage_partition.h" |
| #include "webkit/browser/fileapi/file_system_context.h" |
| #include "webkit/browser/fileapi/file_system_file_util.h" |
| #include "webkit/browser/fileapi/file_system_operation_context.h" |
| #include "webkit/browser/fileapi/file_system_operation_runner.h" |
| #include "webkit/browser/fileapi/file_system_url.h" |
| #include "webkit/common/fileapi/file_system_types.h" |
| #include "webkit/common/fileapi/file_system_util.h" |
| |
| using chromeos::disks::DiskMountManager; |
| using content::BrowserContext; |
| using content::BrowserThread; |
| using content::ChildProcessSecurityPolicy; |
| using content::WebContents; |
| using fileapi::FileSystemURL; |
| |
| namespace extensions { |
| namespace { |
| |
| // Error messages. |
| const char kFileError[] = "File error %d"; |
| |
| const DiskMountManager::Disk* GetVolumeAsDisk(const std::string& mount_path) { |
| DiskMountManager* disk_mount_manager = DiskMountManager::GetInstance(); |
| |
| DiskMountManager::MountPointMap::const_iterator mount_point_it = |
| disk_mount_manager->mount_points().find(mount_path); |
| if (mount_point_it == disk_mount_manager->mount_points().end()) |
| return NULL; |
| |
| const DiskMountManager::Disk* disk = disk_mount_manager->FindDiskBySourcePath( |
| mount_point_it->second.source_path); |
| |
| return (disk && disk->is_hidden()) ? NULL : disk; |
| } |
| |
| base::DictionaryValue* CreateValueFromDisk( |
| Profile* profile, |
| const std::string& extension_id, |
| const DiskMountManager::Disk* volume) { |
| base::DictionaryValue* volume_info = new base::DictionaryValue(); |
| |
| std::string mount_path; |
| if (!volume->mount_path().empty()) { |
| base::FilePath relative_mount_path; |
| file_manager::util::ConvertAbsoluteFilePathToRelativeFileSystemPath( |
| profile, extension_id, base::FilePath(volume->mount_path()), |
| &relative_mount_path); |
| mount_path = relative_mount_path.value(); |
| } |
| |
| volume_info->SetString("devicePath", volume->device_path()); |
| volume_info->SetString("mountPath", mount_path); |
| volume_info->SetString("systemPath", volume->system_path()); |
| volume_info->SetString("filePath", volume->file_path()); |
| volume_info->SetString("deviceLabel", volume->device_label()); |
| volume_info->SetString("driveLabel", volume->drive_label()); |
| volume_info->SetString( |
| "deviceType", |
| DiskMountManager::DeviceTypeToString(volume->device_type())); |
| volume_info->SetDouble("totalSize", |
| static_cast<double>(volume->total_size_in_bytes())); |
| volume_info->SetBoolean("isParent", volume->is_parent()); |
| volume_info->SetBoolean("isReadOnly", volume->is_read_only()); |
| volume_info->SetBoolean("hasMedia", volume->has_media()); |
| volume_info->SetBoolean("isOnBootDevice", volume->on_boot_device()); |
| |
| return volume_info; |
| } |
| |
| base::DictionaryValue* CreateDownloadsVolumeMetadata() { |
| base::DictionaryValue* volume_info = new base::DictionaryValue; |
| volume_info->SetString("mountPath", "Downloads"); |
| volume_info->SetBoolean("isReadOnly", false); |
| return volume_info; |
| } |
| |
| // Sets permissions for the Drive mount point so Files.app can access files |
| // in the mount point directory. It's safe to call this function even if |
| // Drive is disabled by the setting (i.e. prefs::kDisableDrive is true). |
| void SetDriveMountPointPermissions( |
| Profile* profile, |
| const std::string& extension_id, |
| content::RenderViewHost* render_view_host) { |
| if (!render_view_host || |
| !render_view_host->GetSiteInstance() || !render_view_host->GetProcess()) { |
| return; |
| } |
| |
| fileapi::ExternalFileSystemBackend* backend = |
| file_manager::util::GetFileSystemContextForRenderViewHost( |
| profile, render_view_host)->external_backend(); |
| if (!backend) |
| return; |
| |
| const base::FilePath mount_point = drive::util::GetDriveMountPointPath(); |
| // Grant R/W permissions to drive 'folder'. File API layer still |
| // expects this to be satisfied. |
| ChildProcessSecurityPolicy::GetInstance()->GrantCreateReadWriteFile( |
| render_view_host->GetProcess()->GetID(), mount_point); |
| |
| base::FilePath mount_point_virtual; |
| if (backend->GetVirtualPath(mount_point, &mount_point_virtual)) |
| backend->GrantFileAccessToExtension(extension_id, mount_point_virtual); |
| } |
| |
| // Retrieves total and remaining available size on |mount_path|. |
| void GetSizeStatsOnBlockingPool(const std::string& mount_path, |
| uint64* total_size, |
| uint64* remaining_size) { |
| struct statvfs stat = {}; // Zero-clear |
| if (HANDLE_EINTR(statvfs(mount_path.c_str(), &stat)) == 0) { |
| *total_size = |
| static_cast<uint64>(stat.f_blocks) * stat.f_frsize; |
| *remaining_size = |
| static_cast<uint64>(stat.f_bavail) * stat.f_frsize; |
| } |
| } |
| |
| // Retrieves the maximum file name length of the file system of |path|. |
| // Returns 0 if it could not be queried. |
| size_t GetFileNameMaxLengthOnBlockingPool(const std::string& path) { |
| struct statvfs stat = {}; |
| if (HANDLE_EINTR(statvfs(path.c_str(), &stat)) != 0) { |
| // The filesystem seems not supporting statvfs(). Assume it to be a commonly |
| // used bound 255, and log the failure. |
| LOG(ERROR) << "Cannot statvfs() the name length limit for: " << path; |
| return 255; |
| } |
| return stat.f_namemax; |
| } |
| |
| // Sets last modified date. |
| bool SetLastModifiedOnBlockingPool(const base::FilePath& local_path, |
| time_t timestamp) { |
| if (local_path.empty()) |
| return false; |
| |
| struct stat stat_buffer; |
| if (stat(local_path.value().c_str(), &stat_buffer) != 0) |
| return false; |
| |
| struct utimbuf times; |
| times.actime = stat_buffer.st_atime; |
| times.modtime = timestamp; |
| return utime(local_path.value().c_str(), ×) == 0; |
| } |
| |
| // Notifies the copy completion to extensions via event router. |
| void NotifyCopyCompletion( |
| void* profile_id, |
| fileapi::FileSystemOperationRunner::OperationID operation_id, |
| const FileSystemURL& dest_url, |
| base::PlatformFileError error) { |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| |
| // |profile_id| needs to be checked with ProfileManager::IsValidProfile |
| // before using it. |
| Profile* profile = reinterpret_cast<Profile*>(profile_id); |
| if (!g_browser_process->profile_manager()->IsValidProfile(profile)) |
| return; |
| |
| file_manager::EventRouter* event_router = |
| file_manager::FileBrowserPrivateAPI::Get(profile)->event_router(); |
| event_router->OnCopyCompleted(operation_id, dest_url.ToGURL(), error); |
| } |
| |
| // Callback invoked upon completion of Copy() (regardless of succeeded or |
| // failed). |
| void OnCopyCompleted( |
| void* profile_id, |
| fileapi::FileSystemOperationRunner::OperationID* operation_id, |
| const FileSystemURL& dest_url, |
| base::PlatformFileError error) { |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| |
| BrowserThread::PostTask( |
| BrowserThread::UI, FROM_HERE, |
| base::Bind(&NotifyCopyCompletion, |
| profile_id, *operation_id, dest_url, error)); |
| } |
| |
| // Starts the copy operation via FileSystemOperationRunner. |
| fileapi::FileSystemOperationRunner::OperationID StartCopyOnIOThread( |
| void* profile_id, |
| scoped_refptr<fileapi::FileSystemContext> file_system_context, |
| const FileSystemURL& source_url, |
| const FileSystemURL& dest_url) { |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| |
| // Note: |operation_id| is owned by the callback for |
| // FileSystemOperationRunner::Copy(). It is always called in the next message |
| // loop or later, so at least during this invocation it should alive. |
| fileapi::FileSystemOperationRunner::OperationID* operation_id = |
| new fileapi::FileSystemOperationRunner::OperationID; |
| *operation_id = file_system_context->operation_runner()->Copy( |
| source_url, dest_url, |
| fileapi::FileSystemOperationRunner::CopyProgressCallback(), |
| base::Bind(&OnCopyCompleted, |
| profile_id, base::Owned(operation_id), dest_url)); |
| return *operation_id; |
| } |
| |
| void OnCopyCancelled(base::PlatformFileError error) { |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| |
| // We just ignore the status if the copy is actually cancelled or not, |
| // because failing cancellation means the operation is not running now. |
| DLOG_IF(WARNING, error != base::PLATFORM_FILE_OK) |
| << "Failed to cancel copy: " << error; |
| } |
| |
| // Cancels the running copy operation identified by |operation_id|. |
| void CancelCopyOnIOThread( |
| scoped_refptr<fileapi::FileSystemContext> file_system_context, |
| fileapi::FileSystemOperationRunner::OperationID operation_id) { |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| |
| file_system_context->operation_runner()->Cancel( |
| operation_id, base::Bind(&OnCopyCancelled)); |
| } |
| |
| } // namespace |
| |
| FileBrowserPrivateRequestFileSystemFunction:: |
| FileBrowserPrivateRequestFileSystemFunction() { |
| } |
| |
| FileBrowserPrivateRequestFileSystemFunction:: |
| ~FileBrowserPrivateRequestFileSystemFunction() { |
| } |
| |
| void FileBrowserPrivateRequestFileSystemFunction::DidOpenFileSystem( |
| scoped_refptr<fileapi::FileSystemContext> file_system_context, |
| base::PlatformFileError result, |
| const std::string& name, |
| const GURL& root_url) { |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| |
| if (result != base::PLATFORM_FILE_OK) { |
| DidFail(result); |
| return; |
| } |
| |
| // RenderViewHost may have gone while the task is posted asynchronously. |
| if (!render_view_host()) { |
| DidFail(base::PLATFORM_FILE_ERROR_FAILED); |
| return; |
| } |
| |
| // Set up file permission access. |
| const int child_id = render_view_host()->GetProcess()->GetID(); |
| if (!SetupFileSystemAccessPermissions(file_system_context, |
| child_id, |
| GetExtension())) { |
| DidFail(base::PLATFORM_FILE_ERROR_SECURITY); |
| return; |
| } |
| |
| // Set permissions for the Drive mount point immediately when we kick of |
| // first instance of file manager. The actual mount event will be sent to |
| // UI only when we perform proper authentication. |
| // |
| // Note that we call this function even when Drive is disabled by the |
| // setting. Otherwise, we need to call this when the setting is changed at |
| // a later time, which complicates the code. |
| SetDriveMountPointPermissions(profile_, extension_id(), render_view_host()); |
| |
| DictionaryValue* dict = new DictionaryValue(); |
| SetResult(dict); |
| dict->SetString("name", name); |
| dict->SetString("root_url", root_url.spec()); |
| dict->SetInteger("error", drive::FILE_ERROR_OK); |
| SendResponse(true); |
| } |
| |
| void FileBrowserPrivateRequestFileSystemFunction::DidFail( |
| base::PlatformFileError error_code) { |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| |
| error_ = base::StringPrintf(kFileError, static_cast<int>(error_code)); |
| SendResponse(false); |
| } |
| |
| bool FileBrowserPrivateRequestFileSystemFunction:: |
| SetupFileSystemAccessPermissions( |
| scoped_refptr<fileapi::FileSystemContext> file_system_context, |
| int child_id, |
| scoped_refptr<const extensions::Extension> extension) { |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| |
| if (!extension.get()) |
| return false; |
| |
| // Make sure that only component extension can access the entire |
| // local file system. |
| if (extension_->location() != extensions::Manifest::COMPONENT) { |
| NOTREACHED() << "Private method access by non-component extension " |
| << extension->id(); |
| return false; |
| } |
| |
| fileapi::ExternalFileSystemBackend* backend = |
| file_system_context->external_backend(); |
| if (!backend) |
| return false; |
| |
| // Grant full access to File API from this component extension. |
| backend->GrantFullAccessToExtension(extension_->id()); |
| |
| // Grant R/W file permissions to the renderer hosting component |
| // extension for all paths exposed by our local file system backend. |
| std::vector<base::FilePath> root_dirs = backend->GetRootDirectories(); |
| for (size_t i = 0; i < root_dirs.size(); ++i) { |
| ChildProcessSecurityPolicy::GetInstance()->GrantCreateReadWriteFile( |
| child_id, root_dirs[i]); |
| } |
| return true; |
| } |
| |
| bool FileBrowserPrivateRequestFileSystemFunction::RunImpl() { |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| using extensions::api::file_browser_private::RequestFileSystem::Params; |
| const scoped_ptr<Params> params(Params::Create(*args_)); |
| EXTENSION_FUNCTION_VALIDATE(params); |
| |
| // TODO(satorux): Handle the file system ID. crbug.com/284963. |
| DCHECK_EQ("compatible", params->file_system_id); |
| |
| if (!dispatcher() || !render_view_host() || !render_view_host()->GetProcess()) |
| return false; |
| |
| set_log_on_completion(true); |
| |
| scoped_refptr<fileapi::FileSystemContext> file_system_context = |
| file_manager::util::GetFileSystemContextForRenderViewHost( |
| profile(), render_view_host()); |
| |
| const GURL origin_url = source_url_.GetOrigin(); |
| file_system_context->OpenFileSystem( |
| origin_url, |
| fileapi::kFileSystemTypeExternal, |
| fileapi::OPEN_FILE_SYSTEM_FAIL_IF_NONEXISTENT, |
| base::Bind(&FileBrowserPrivateRequestFileSystemFunction:: |
| DidOpenFileSystem, |
| this, |
| file_system_context)); |
| return true; |
| } |
| |
| FileWatchFunctionBase::FileWatchFunctionBase() { |
| } |
| |
| FileWatchFunctionBase::~FileWatchFunctionBase() { |
| } |
| |
| void FileWatchFunctionBase::Respond(bool success) { |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| |
| SetResult(Value::CreateBooleanValue(success)); |
| SendResponse(success); |
| } |
| |
| bool FileWatchFunctionBase::RunImpl() { |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| |
| if (!render_view_host() || !render_view_host()->GetProcess()) |
| return false; |
| |
| // First param is url of a file to watch. |
| std::string url; |
| if (!args_->GetString(0, &url) || url.empty()) |
| return false; |
| |
| scoped_refptr<fileapi::FileSystemContext> file_system_context = |
| file_manager::util::GetFileSystemContextForRenderViewHost( |
| profile(), render_view_host()); |
| |
| FileSystemURL file_watch_url = file_system_context->CrackURL(GURL(url)); |
| base::FilePath local_path = file_watch_url.path(); |
| base::FilePath virtual_path = file_watch_url.virtual_path(); |
| if (local_path.empty()) { |
| Respond(false); |
| return true; |
| } |
| PerformFileWatchOperation(local_path, virtual_path, extension_id()); |
| |
| return true; |
| } |
| |
| FileBrowserPrivateAddFileWatchFunction:: |
| FileBrowserPrivateAddFileWatchFunction() { |
| } |
| |
| FileBrowserPrivateAddFileWatchFunction:: |
| ~FileBrowserPrivateAddFileWatchFunction() { |
| } |
| |
| void FileBrowserPrivateAddFileWatchFunction::PerformFileWatchOperation( |
| const base::FilePath& local_path, |
| const base::FilePath& virtual_path, |
| const std::string& extension_id) { |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| |
| file_manager::EventRouter* event_router = |
| file_manager::FileBrowserPrivateAPI::Get(profile_)->event_router(); |
| event_router->AddFileWatch( |
| local_path, |
| virtual_path, |
| extension_id, |
| base::Bind(&FileBrowserPrivateAddFileWatchFunction::Respond, this)); |
| } |
| |
| FileBrowserPrivateRemoveFileWatchFunction:: |
| FileBrowserPrivateRemoveFileWatchFunction() { |
| } |
| |
| FileBrowserPrivateRemoveFileWatchFunction:: |
| ~FileBrowserPrivateRemoveFileWatchFunction() { |
| } |
| |
| void FileBrowserPrivateRemoveFileWatchFunction::PerformFileWatchOperation( |
| const base::FilePath& local_path, |
| const base::FilePath& unused, |
| const std::string& extension_id) { |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| |
| file_manager::EventRouter* event_router = |
| file_manager::FileBrowserPrivateAPI::Get(profile_)->event_router(); |
| event_router->RemoveFileWatch(local_path, extension_id); |
| Respond(true); |
| } |
| |
| FileBrowserPrivateSetLastModifiedFunction:: |
| FileBrowserPrivateSetLastModifiedFunction() { |
| } |
| |
| FileBrowserPrivateSetLastModifiedFunction:: |
| ~FileBrowserPrivateSetLastModifiedFunction() { |
| } |
| |
| bool FileBrowserPrivateSetLastModifiedFunction::RunImpl() { |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| |
| if (args_->GetSize() != 2) { |
| return false; |
| } |
| |
| std::string file_url; |
| if (!args_->GetString(0, &file_url)) |
| return false; |
| |
| std::string timestamp; |
| if (!args_->GetString(1, ×tamp)) |
| return false; |
| |
| base::FilePath local_path = file_manager::util::GetLocalPathFromURL( |
| render_view_host(), profile(), GURL(file_url)); |
| |
| base::PostTaskAndReplyWithResult( |
| BrowserThread::GetBlockingPool(), |
| FROM_HERE, |
| base::Bind(&SetLastModifiedOnBlockingPool, |
| local_path, |
| strtoul(timestamp.c_str(), NULL, 0)), |
| base::Bind(&FileBrowserPrivateSetLastModifiedFunction::SendResponse, |
| this)); |
| return true; |
| } |
| |
| FileBrowserPrivateGetSizeStatsFunction:: |
| FileBrowserPrivateGetSizeStatsFunction() { |
| } |
| |
| FileBrowserPrivateGetSizeStatsFunction:: |
| ~FileBrowserPrivateGetSizeStatsFunction() { |
| } |
| |
| bool FileBrowserPrivateGetSizeStatsFunction::RunImpl() { |
| if (args_->GetSize() != 1) { |
| return false; |
| } |
| |
| std::string mount_url; |
| if (!args_->GetString(0, &mount_url)) |
| return false; |
| |
| base::FilePath file_path = file_manager::util::GetLocalPathFromURL( |
| render_view_host(), profile(), GURL(mount_url)); |
| if (file_path.empty()) |
| return false; |
| |
| if (file_path == drive::util::GetDriveMountPointPath()) { |
| drive::FileSystemInterface* file_system = |
| drive::util::GetFileSystemByProfile(profile()); |
| if (!file_system) { |
| // |file_system| is NULL if Drive is disabled. |
| // If stats couldn't be gotten for drive, result should be left |
| // undefined. See comments in GetDriveAvailableSpaceCallback(). |
| SendResponse(true); |
| return true; |
| } |
| |
| file_system->GetAvailableSpace( |
| base::Bind(&FileBrowserPrivateGetSizeStatsFunction:: |
| GetDriveAvailableSpaceCallback, |
| this)); |
| } else { |
| uint64* total_size = new uint64(0); |
| uint64* remaining_size = new uint64(0); |
| BrowserThread::PostBlockingPoolTaskAndReply( |
| FROM_HERE, |
| base::Bind(&GetSizeStatsOnBlockingPool, |
| file_path.value(), |
| total_size, |
| remaining_size), |
| base::Bind(&FileBrowserPrivateGetSizeStatsFunction:: |
| GetSizeStatsCallback, |
| this, |
| base::Owned(total_size), |
| base::Owned(remaining_size))); |
| } |
| return true; |
| } |
| |
| void FileBrowserPrivateGetSizeStatsFunction::GetDriveAvailableSpaceCallback( |
| drive::FileError error, |
| int64 bytes_total, |
| int64 bytes_used) { |
| if (error == drive::FILE_ERROR_OK) { |
| const uint64 bytes_total_unsigned = bytes_total; |
| const uint64 bytes_remaining_unsigned = bytes_total - bytes_used; |
| GetSizeStatsCallback(&bytes_total_unsigned, |
| &bytes_remaining_unsigned); |
| } else { |
| // If stats couldn't be gotten for drive, result should be left undefined. |
| SendResponse(true); |
| } |
| } |
| |
| void FileBrowserPrivateGetSizeStatsFunction::GetSizeStatsCallback( |
| const uint64* total_size, |
| const uint64* remaining_size) { |
| base::DictionaryValue* sizes = new base::DictionaryValue(); |
| SetResult(sizes); |
| |
| sizes->SetDouble("totalSize", static_cast<double>(*total_size)); |
| sizes->SetDouble("remainingSize", static_cast<double>(*remaining_size)); |
| |
| SendResponse(true); |
| } |
| |
| FileBrowserPrivateGetVolumeMetadataFunction:: |
| FileBrowserPrivateGetVolumeMetadataFunction() { |
| } |
| |
| FileBrowserPrivateGetVolumeMetadataFunction:: |
| ~FileBrowserPrivateGetVolumeMetadataFunction() { |
| } |
| |
| bool FileBrowserPrivateGetVolumeMetadataFunction::RunImpl() { |
| if (args_->GetSize() != 1) { |
| error_ = "Invalid argument count"; |
| return false; |
| } |
| |
| std::string volume_mount_url; |
| if (!args_->GetString(0, &volume_mount_url)) { |
| NOTREACHED(); |
| return false; |
| } |
| |
| base::FilePath file_path = file_manager::util::GetLocalPathFromURL( |
| render_view_host(), profile(), GURL(volume_mount_url)); |
| if (file_path.empty()) { |
| error_ = "Invalid mount path."; |
| return false; |
| } |
| |
| results_.reset(); |
| |
| base::FilePath home_path; |
| // TODO(hidehiko): Return the volume info for Drive File System. |
| if (PathService::Get(base::DIR_HOME, &home_path) && |
| file_path == home_path.AppendASCII("Downloads")) { |
| // Return simple (fake) volume metadata for Downloads volume. |
| SetResult(CreateDownloadsVolumeMetadata()); |
| } else { |
| const DiskMountManager::Disk* volume = GetVolumeAsDisk(file_path.value()); |
| if (volume) |
| SetResult(CreateValueFromDisk(profile_, extension_->id(), volume)); |
| } |
| |
| SendResponse(true); |
| return true; |
| } |
| |
| FileBrowserPrivateValidatePathNameLengthFunction:: |
| FileBrowserPrivateValidatePathNameLengthFunction() { |
| } |
| |
| FileBrowserPrivateValidatePathNameLengthFunction:: |
| ~FileBrowserPrivateValidatePathNameLengthFunction() { |
| } |
| |
| bool FileBrowserPrivateValidatePathNameLengthFunction::RunImpl() { |
| std::string parent_url; |
| if (!args_->GetString(0, &parent_url)) |
| return false; |
| |
| std::string name; |
| if (!args_->GetString(1, &name)) |
| return false; |
| |
| scoped_refptr<fileapi::FileSystemContext> file_system_context = |
| file_manager::util::GetFileSystemContextForRenderViewHost( |
| profile(), render_view_host()); |
| |
| fileapi::FileSystemURL filesystem_url( |
| file_system_context->CrackURL(GURL(parent_url))); |
| if (!chromeos::FileSystemBackend::CanHandleURL(filesystem_url)) |
| return false; |
| |
| // No explicit limit on the length of Drive file names. |
| if (filesystem_url.type() == fileapi::kFileSystemTypeDrive) { |
| SetResult(new base::FundamentalValue(true)); |
| SendResponse(true); |
| return true; |
| } |
| |
| base::PostTaskAndReplyWithResult( |
| BrowserThread::GetBlockingPool(), |
| FROM_HERE, |
| base::Bind(&GetFileNameMaxLengthOnBlockingPool, |
| filesystem_url.path().AsUTF8Unsafe()), |
| base::Bind(&FileBrowserPrivateValidatePathNameLengthFunction:: |
| OnFilePathLimitRetrieved, |
| this, name.size())); |
| return true; |
| } |
| |
| void FileBrowserPrivateValidatePathNameLengthFunction::OnFilePathLimitRetrieved( |
| size_t current_length, |
| size_t max_length) { |
| SetResult(new base::FundamentalValue(current_length <= max_length)); |
| SendResponse(true); |
| } |
| |
| FileBrowserPrivateFormatDeviceFunction:: |
| FileBrowserPrivateFormatDeviceFunction() { |
| } |
| |
| FileBrowserPrivateFormatDeviceFunction:: |
| ~FileBrowserPrivateFormatDeviceFunction() { |
| } |
| |
| bool FileBrowserPrivateFormatDeviceFunction::RunImpl() { |
| if (args_->GetSize() != 1) { |
| return false; |
| } |
| |
| std::string volume_file_url; |
| if (!args_->GetString(0, &volume_file_url)) { |
| NOTREACHED(); |
| return false; |
| } |
| |
| base::FilePath file_path = file_manager::util::GetLocalPathFromURL( |
| render_view_host(), profile(), GURL(volume_file_url)); |
| if (file_path.empty()) |
| return false; |
| |
| DiskMountManager::GetInstance()->FormatMountedDevice(file_path.value()); |
| SendResponse(true); |
| return true; |
| } |
| |
| FileBrowserPrivateStartCopyFunction::FileBrowserPrivateStartCopyFunction() { |
| } |
| |
| FileBrowserPrivateStartCopyFunction::~FileBrowserPrivateStartCopyFunction() { |
| } |
| |
| bool FileBrowserPrivateStartCopyFunction::RunImpl() { |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| |
| using extensions::api::file_browser_private::StartCopy::Params; |
| const scoped_ptr<Params> params(Params::Create(*args_)); |
| EXTENSION_FUNCTION_VALIDATE(params); |
| |
| if (params->source_url.empty() || params->parent.empty() || |
| params->new_name.empty()) { |
| error_ = base::IntToString(fileapi::PlatformFileErrorToWebFileError( |
| base::PLATFORM_FILE_ERROR_INVALID_URL)); |
| return false; |
| } |
| |
| scoped_refptr<fileapi::FileSystemContext> file_system_context = |
| file_manager::util::GetFileSystemContextForRenderViewHost( |
| profile(), render_view_host()); |
| |
| fileapi::FileSystemURL source_url( |
| file_system_context->CrackURL(GURL(params->source_url))); |
| fileapi::FileSystemURL dest_url(file_system_context->CrackURL( |
| GURL(params->parent + "/" + params->new_name))); |
| |
| if (!source_url.is_valid() || !dest_url.is_valid()) { |
| error_ = base::IntToString(fileapi::PlatformFileErrorToWebFileError( |
| base::PLATFORM_FILE_ERROR_INVALID_URL)); |
| return false; |
| } |
| |
| return BrowserThread::PostTaskAndReplyWithResult( |
| BrowserThread::IO, |
| FROM_HERE, |
| base::Bind(&StartCopyOnIOThread, |
| profile(), file_system_context, source_url, dest_url), |
| base::Bind(&FileBrowserPrivateStartCopyFunction::RunAfterStartCopy, |
| this)); |
| } |
| |
| void FileBrowserPrivateStartCopyFunction::RunAfterStartCopy( |
| int operation_id) { |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| |
| SetResult(Value::CreateIntegerValue(operation_id)); |
| SendResponse(true); |
| } |
| |
| FileBrowserPrivateCancelCopyFunction::FileBrowserPrivateCancelCopyFunction() { |
| } |
| |
| FileBrowserPrivateCancelCopyFunction::~FileBrowserPrivateCancelCopyFunction() { |
| } |
| |
| bool FileBrowserPrivateCancelCopyFunction::RunImpl() { |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| |
| using extensions::api::file_browser_private::CancelCopy::Params; |
| const scoped_ptr<Params> params(Params::Create(*args_)); |
| EXTENSION_FUNCTION_VALIDATE(params); |
| |
| scoped_refptr<fileapi::FileSystemContext> file_system_context = |
| file_manager::util::GetFileSystemContextForRenderViewHost( |
| profile(), render_view_host()); |
| |
| // We don't much take care about the result of cancellation. |
| BrowserThread::PostTask( |
| BrowserThread::IO, |
| FROM_HERE, |
| base::Bind(&CancelCopyOnIOThread, file_system_context, params->copy_id)); |
| SendResponse(true); |
| return true; |
| } |
| |
| } // namespace extensions |