private_api_mount.cc revision f8ee788a64d60abd8f2d742a5fdedde054ecd910
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_mount.h" 6 7#include <string> 8 9#include "base/file_util.h" 10#include "base/format_macros.h" 11#include "chrome/browser/chromeos/drive/file_system_interface.h" 12#include "chrome/browser/chromeos/drive/file_system_util.h" 13#include "chrome/browser/chromeos/extensions/file_manager/private_api_util.h" 14#include "chrome/browser/chromeos/file_manager/fileapi_util.h" 15#include "chrome/browser/chromeos/file_manager/volume_manager.h" 16#include "chrome/browser/drive/event_logger.h" 17#include "chrome/browser/profiles/profile.h" 18#include "chrome/common/extensions/api/file_browser_private.h" 19#include "chromeos/disks/disk_mount_manager.h" 20#include "content/public/browser/browser_thread.h" 21#include "google_apis/drive/task_util.h" 22#include "ui/shell_dialogs/selected_file_info.h" 23 24using chromeos::disks::DiskMountManager; 25using content::BrowserThread; 26namespace file_browser_private = extensions::api::file_browser_private; 27 28namespace extensions { 29 30namespace { 31 32// Does chmod o+r for the given path to ensure the file is readable from avfs. 33void EnsureReadableFilePermissionOnBlockingPool( 34 const base::FilePath& path, 35 const base::Callback<void(drive::FileError, const base::FilePath&)>& 36 callback) { 37 int mode = 0; 38 if (!base::GetPosixFilePermissions(path, &mode) || 39 !base::SetPosixFilePermissions(path, mode | S_IROTH)) { 40 callback.Run(drive::FILE_ERROR_ACCESS_DENIED, base::FilePath()); 41 return; 42 } 43 callback.Run(drive::FILE_ERROR_OK, path); 44} 45 46} // namespace 47 48bool FileBrowserPrivateAddMountFunction::RunAsync() { 49 using file_browser_private::AddMount::Params; 50 const scoped_ptr<Params> params(Params::Create(*args_)); 51 EXTENSION_FUNCTION_VALIDATE(params); 52 53 drive::EventLogger* logger = file_manager::util::GetLogger(GetProfile()); 54 if (logger) { 55 logger->Log(logging::LOG_INFO, 56 "%s[%d] called. (source: '%s')", 57 name().c_str(), 58 request_id(), 59 params->source.empty() ? "(none)" : params->source.c_str()); 60 } 61 set_log_on_completion(true); 62 63 const base::FilePath path = file_manager::util::GetLocalPathFromURL( 64 render_view_host(), GetProfile(), GURL(params->source)); 65 66 if (path.empty()) 67 return false; 68 69 // Check if the source path is under Drive cache directory. 70 if (drive::util::IsUnderDriveMountPoint(path)) { 71 drive::FileSystemInterface* file_system = 72 drive::util::GetFileSystemByProfile(GetProfile()); 73 if (!file_system) 74 return false; 75 76 file_system->MarkCacheFileAsMounted( 77 drive::util::ExtractDrivePath(path), 78 base::Bind( 79 &FileBrowserPrivateAddMountFunction::RunAfterMarkCacheFileAsMounted, 80 this, path.BaseName())); 81 } else { 82 file_manager::VolumeManager* volume_manager = 83 file_manager::VolumeManager::Get(GetProfile()); 84 DCHECK(volume_manager); 85 86 bool is_under_downloads = false; 87 const std::vector<file_manager::VolumeInfo> volumes = 88 volume_manager->GetVolumeInfoList(); 89 for (size_t i = 0; i < volumes.size(); ++i) { 90 if (volumes[i].type == file_manager::VOLUME_TYPE_DOWNLOADS_DIRECTORY && 91 volumes[i].mount_path.IsParent(path)) { 92 is_under_downloads = true; 93 break; 94 } 95 } 96 97 if (is_under_downloads) { 98 // For files under downloads, change the file permission and make it 99 // readable from avfs/fuse if needed. 100 BrowserThread::PostBlockingPoolTask( 101 FROM_HERE, 102 base::Bind(&EnsureReadableFilePermissionOnBlockingPool, 103 path, 104 google_apis::CreateRelayCallback( 105 base::Bind(&FileBrowserPrivateAddMountFunction:: 106 RunAfterMarkCacheFileAsMounted, 107 this, 108 path.BaseName())))); 109 } else { 110 RunAfterMarkCacheFileAsMounted( 111 path.BaseName(), drive::FILE_ERROR_OK, path); 112 } 113 } 114 return true; 115} 116 117void FileBrowserPrivateAddMountFunction::RunAfterMarkCacheFileAsMounted( 118 const base::FilePath& display_name, 119 drive::FileError error, 120 const base::FilePath& file_path) { 121 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 122 123 if (error != drive::FILE_ERROR_OK) { 124 SendResponse(false); 125 return; 126 } 127 128 // Pass back the actual source path of the mount point. 129 SetResult(new base::StringValue(file_path.AsUTF8Unsafe())); 130 SendResponse(true); 131 132 // MountPath() takes a std::string. 133 DiskMountManager* disk_mount_manager = DiskMountManager::GetInstance(); 134 disk_mount_manager->MountPath( 135 file_path.AsUTF8Unsafe(), 136 base::FilePath(display_name.Extension()).AsUTF8Unsafe(), 137 display_name.AsUTF8Unsafe(), 138 chromeos::MOUNT_TYPE_ARCHIVE); 139} 140 141bool FileBrowserPrivateRemoveMountFunction::RunAsync() { 142 using file_browser_private::RemoveMount::Params; 143 const scoped_ptr<Params> params(Params::Create(*args_)); 144 EXTENSION_FUNCTION_VALIDATE(params); 145 146 drive::EventLogger* logger = file_manager::util::GetLogger(GetProfile()); 147 if (logger) { 148 logger->Log(logging::LOG_INFO, 149 "%s[%d] called. (volume_id: '%s')", 150 name().c_str(), 151 request_id(), 152 params->volume_id.c_str()); 153 } 154 set_log_on_completion(true); 155 156 using file_manager::VolumeManager; 157 using file_manager::VolumeInfo; 158 VolumeManager* volume_manager = VolumeManager::Get(GetProfile()); 159 DCHECK(volume_manager); 160 161 VolumeInfo volume_info; 162 if (!volume_manager->FindVolumeInfoById(params->volume_id, &volume_info)) 163 return false; 164 165 // TODO(tbarzic): Send response when callback is received, it would make more 166 // sense than remembering issued unmount requests in file manager and showing 167 // errors for them when MountCompleted event is received. 168 switch (volume_info.type) { 169 case file_manager::VOLUME_TYPE_REMOVABLE_DISK_PARTITION: 170 case file_manager::VOLUME_TYPE_MOUNTED_ARCHIVE_FILE: { 171 DiskMountManager::GetInstance()->UnmountPath( 172 volume_info.mount_path.value(), 173 chromeos::UNMOUNT_OPTIONS_NONE, 174 DiskMountManager::UnmountPathCallback()); 175 break; 176 } 177 case file_manager::VOLUME_TYPE_PROVIDED: { 178 chromeos::file_system_provider::Service* service = 179 chromeos::file_system_provider::Service::Get(GetProfile()); 180 DCHECK(service); 181 // TODO(mtomasz): Pass a more detailed error than just a bool. 182 if (!service->RequestUnmount(volume_info.extension_id, 183 volume_info.file_system_id)) { 184 return false; 185 } 186 break; 187 } 188 default: 189 // Requested unmounting a device which is not unmountable. 190 return false; 191 } 192 193 SendResponse(true); 194 return true; 195} 196 197bool FileBrowserPrivateGetVolumeMetadataListFunction::RunAsync() { 198 if (args_->GetSize()) 199 return false; 200 201 const std::vector<file_manager::VolumeInfo>& volume_info_list = 202 file_manager::VolumeManager::Get(GetProfile())->GetVolumeInfoList(); 203 204 std::string log_string; 205 std::vector<linked_ptr<file_browser_private::VolumeMetadata> > result; 206 for (size_t i = 0; i < volume_info_list.size(); ++i) { 207 linked_ptr<file_browser_private::VolumeMetadata> volume_metadata( 208 new file_browser_private::VolumeMetadata); 209 file_manager::util::VolumeInfoToVolumeMetadata( 210 GetProfile(), volume_info_list[i], volume_metadata.get()); 211 result.push_back(volume_metadata); 212 if (!log_string.empty()) 213 log_string += ", "; 214 log_string += volume_info_list[i].mount_path.AsUTF8Unsafe(); 215 } 216 217 drive::EventLogger* logger = file_manager::util::GetLogger(GetProfile()); 218 if (logger) { 219 logger->Log(logging::LOG_INFO, 220 "%s[%d] succeeded. (results: '[%s]', %" PRIuS " mount points)", 221 name().c_str(), request_id(), log_string.c_str(), 222 result.size()); 223 } 224 225 results_ = 226 file_browser_private::GetVolumeMetadataList::Results::Create(result); 227 SendResponse(true); 228 return true; 229} 230 231} // namespace extensions 232