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/files/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_manager_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_manager_private = extensions::api::file_manager_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 FileManagerPrivateAddMountFunction::RunAsync() { 49 using file_manager_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 // Ensure that the cache file exists. 77 const base::FilePath drive_path = drive::util::ExtractDrivePath(path); 78 file_system->GetFile( 79 drive_path, 80 base::Bind(&FileManagerPrivateAddMountFunction::RunAfterGetDriveFile, 81 this, 82 drive_path)); 83 } else { 84 file_manager::VolumeManager* volume_manager = 85 file_manager::VolumeManager::Get(GetProfile()); 86 DCHECK(volume_manager); 87 88 bool is_under_downloads = false; 89 const std::vector<file_manager::VolumeInfo> volumes = 90 volume_manager->GetVolumeInfoList(); 91 for (size_t i = 0; i < volumes.size(); ++i) { 92 if (volumes[i].type == file_manager::VOLUME_TYPE_DOWNLOADS_DIRECTORY && 93 volumes[i].mount_path.IsParent(path)) { 94 is_under_downloads = true; 95 break; 96 } 97 } 98 99 if (is_under_downloads) { 100 // For files under downloads, change the file permission and make it 101 // readable from avfs/fuse if needed. 102 BrowserThread::PostBlockingPoolTask( 103 FROM_HERE, 104 base::Bind(&EnsureReadableFilePermissionOnBlockingPool, 105 path, 106 google_apis::CreateRelayCallback( 107 base::Bind(&FileManagerPrivateAddMountFunction:: 108 RunAfterMarkCacheFileAsMounted, 109 this, 110 path.BaseName())))); 111 } else { 112 RunAfterMarkCacheFileAsMounted( 113 path.BaseName(), drive::FILE_ERROR_OK, path); 114 } 115 } 116 return true; 117} 118 119void FileManagerPrivateAddMountFunction::RunAfterGetDriveFile( 120 const base::FilePath& drive_path, 121 drive::FileError error, 122 const base::FilePath& cache_path, 123 scoped_ptr<drive::ResourceEntry> entry) { 124 DCHECK_CURRENTLY_ON(BrowserThread::UI); 125 126 if (error != drive::FILE_ERROR_OK) { 127 SendResponse(false); 128 return; 129 } 130 131 drive::FileSystemInterface* const file_system = 132 drive::util::GetFileSystemByProfile(GetProfile()); 133 if (!file_system) { 134 SendResponse(false); 135 return; 136 } 137 138 file_system->MarkCacheFileAsMounted( 139 drive_path, 140 base::Bind( 141 &FileManagerPrivateAddMountFunction::RunAfterMarkCacheFileAsMounted, 142 this, 143 drive_path.BaseName())); 144} 145 146void FileManagerPrivateAddMountFunction::RunAfterMarkCacheFileAsMounted( 147 const base::FilePath& display_name, 148 drive::FileError error, 149 const base::FilePath& file_path) { 150 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 151 152 if (error != drive::FILE_ERROR_OK) { 153 SendResponse(false); 154 return; 155 } 156 157 // Pass back the actual source path of the mount point. 158 SetResult(new base::StringValue(file_path.AsUTF8Unsafe())); 159 SendResponse(true); 160 161 // MountPath() takes a std::string. 162 DiskMountManager* disk_mount_manager = DiskMountManager::GetInstance(); 163 disk_mount_manager->MountPath( 164 file_path.AsUTF8Unsafe(), 165 base::FilePath(display_name.Extension()).AsUTF8Unsafe(), 166 display_name.AsUTF8Unsafe(), 167 chromeos::MOUNT_TYPE_ARCHIVE); 168} 169 170bool FileManagerPrivateRemoveMountFunction::RunAsync() { 171 using file_manager_private::RemoveMount::Params; 172 const scoped_ptr<Params> params(Params::Create(*args_)); 173 EXTENSION_FUNCTION_VALIDATE(params); 174 175 drive::EventLogger* logger = file_manager::util::GetLogger(GetProfile()); 176 if (logger) { 177 logger->Log(logging::LOG_INFO, 178 "%s[%d] called. (volume_id: '%s')", 179 name().c_str(), 180 request_id(), 181 params->volume_id.c_str()); 182 } 183 set_log_on_completion(true); 184 185 using file_manager::VolumeManager; 186 using file_manager::VolumeInfo; 187 VolumeManager* volume_manager = VolumeManager::Get(GetProfile()); 188 DCHECK(volume_manager); 189 190 VolumeInfo volume_info; 191 if (!volume_manager->FindVolumeInfoById(params->volume_id, &volume_info)) 192 return false; 193 194 // TODO(tbarzic): Send response when callback is received, it would make more 195 // sense than remembering issued unmount requests in file manager and showing 196 // errors for them when MountCompleted event is received. 197 switch (volume_info.type) { 198 case file_manager::VOLUME_TYPE_REMOVABLE_DISK_PARTITION: 199 case file_manager::VOLUME_TYPE_MOUNTED_ARCHIVE_FILE: { 200 DiskMountManager::GetInstance()->UnmountPath( 201 volume_info.mount_path.value(), 202 chromeos::UNMOUNT_OPTIONS_NONE, 203 DiskMountManager::UnmountPathCallback()); 204 break; 205 } 206 case file_manager::VOLUME_TYPE_PROVIDED: { 207 chromeos::file_system_provider::Service* service = 208 chromeos::file_system_provider::Service::Get(GetProfile()); 209 DCHECK(service); 210 // TODO(mtomasz): Pass a more detailed error than just a bool. 211 if (!service->RequestUnmount(volume_info.extension_id, 212 volume_info.file_system_id)) { 213 return false; 214 } 215 break; 216 } 217 default: 218 // Requested unmounting a device which is not unmountable. 219 return false; 220 } 221 222 SendResponse(true); 223 return true; 224} 225 226bool FileManagerPrivateGetVolumeMetadataListFunction::RunAsync() { 227 if (args_->GetSize()) 228 return false; 229 230 const std::vector<file_manager::VolumeInfo>& volume_info_list = 231 file_manager::VolumeManager::Get(GetProfile())->GetVolumeInfoList(); 232 233 std::string log_string; 234 std::vector<linked_ptr<file_manager_private::VolumeMetadata> > result; 235 for (size_t i = 0; i < volume_info_list.size(); ++i) { 236 linked_ptr<file_manager_private::VolumeMetadata> volume_metadata( 237 new file_manager_private::VolumeMetadata); 238 file_manager::util::VolumeInfoToVolumeMetadata( 239 GetProfile(), volume_info_list[i], volume_metadata.get()); 240 result.push_back(volume_metadata); 241 if (!log_string.empty()) 242 log_string += ", "; 243 log_string += volume_info_list[i].mount_path.AsUTF8Unsafe(); 244 } 245 246 drive::EventLogger* logger = file_manager::util::GetLogger(GetProfile()); 247 if (logger) { 248 logger->Log(logging::LOG_INFO, 249 "%s[%d] succeeded. (results: '[%s]', %" PRIuS " mount points)", 250 name().c_str(), request_id(), log_string.c_str(), 251 result.size()); 252 } 253 254 results_ = 255 file_manager_private::GetVolumeMetadataList::Results::Create(result); 256 SendResponse(true); 257 return true; 258} 259 260} // namespace extensions 261