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_util.h" 6 7 #include <string> 8 9 #include "base/files/file_path.h" 10 #include "base/message_loop/message_loop.h" 11 #include "chrome/browser/chromeos/drive/drive.pb.h" 12 #include "chrome/browser/chromeos/drive/drive_integration_service.h" 13 #include "chrome/browser/chromeos/drive/file_errors.h" 14 #include "chrome/browser/chromeos/drive/file_system_interface.h" 15 #include "chrome/browser/chromeos/drive/file_system_util.h" 16 #include "chrome/browser/chromeos/file_manager/app_id.h" 17 #include "chrome/browser/chromeos/file_manager/fileapi_util.h" 18 #include "chrome/browser/chromeos/file_manager/filesystem_api_util.h" 19 #include "chrome/browser/chromeos/file_manager/path_util.h" 20 #include "chrome/browser/chromeos/file_manager/snapshot_manager.h" 21 #include "chrome/browser/chromeos/file_manager/volume_manager.h" 22 #include "chrome/browser/chromeos/fileapi/file_system_backend.h" 23 #include "chrome/browser/profiles/profile.h" 24 #include "chrome/common/extensions/api/file_manager_private.h" 25 #include "content/public/browser/child_process_security_policy.h" 26 #include "storage/browser/fileapi/file_system_context.h" 27 #include "storage/browser/fileapi/file_system_url.h" 28 #include "ui/shell_dialogs/selected_file_info.h" 29 30 namespace file_manager_private = extensions::api::file_manager_private; 31 32 namespace file_manager { 33 namespace util { 34 namespace { 35 36 // The struct is used for GetSelectedFileInfo(). 37 struct GetSelectedFileInfoParams { 38 GetSelectedFileInfoLocalPathOption local_path_option; 39 GetSelectedFileInfoCallback callback; 40 std::vector<base::FilePath> file_paths; 41 std::vector<ui::SelectedFileInfo> selected_files; 42 }; 43 44 // The callback type for GetFileNativeLocalPathFor{Opening,Saving}. It receives 45 // the resolved local path when successful, and receives empty path for failure. 46 typedef base::Callback<void(const base::FilePath&)> LocalPathCallback; 47 48 // Converts a callback from Drive file system to LocalPathCallback. 49 void OnDriveGetFile(const base::FilePath& path, 50 const LocalPathCallback& callback, 51 drive::FileError error, 52 const base::FilePath& local_file_path, 53 scoped_ptr<drive::ResourceEntry> entry) { 54 if (error != drive::FILE_ERROR_OK) 55 DLOG(ERROR) << "Failed to get " << path.value() << " with: " << error; 56 callback.Run(local_file_path); 57 } 58 59 // Gets a resolved local file path of a non native |path| for file opening. 60 void GetFileNativeLocalPathForOpening(Profile* profile, 61 const base::FilePath& path, 62 const LocalPathCallback& callback) { 63 if (drive::util::IsUnderDriveMountPoint(path)) { 64 drive::FileSystemInterface* file_system = 65 drive::util::GetFileSystemByProfile(profile); 66 if (!file_system) { 67 DLOG(ERROR) << "Drive file selected while disabled: " << path.value(); 68 callback.Run(base::FilePath()); 69 return; 70 } 71 file_system->GetFile(drive::util::ExtractDrivePath(path), 72 base::Bind(&OnDriveGetFile, path, callback)); 73 return; 74 } 75 76 VolumeManager::Get(profile)->snapshot_manager()->CreateManagedSnapshot( 77 path, callback); 78 } 79 80 // Gets a resolved local file path of a non native |path| for file saving. 81 void GetFileNativeLocalPathForSaving(Profile* profile, 82 const base::FilePath& path, 83 const LocalPathCallback& callback) { 84 if (drive::util::IsUnderDriveMountPoint(path)) { 85 drive::FileSystemInterface* file_system = 86 drive::util::GetFileSystemByProfile(profile); 87 if (!file_system) { 88 DLOG(ERROR) << "Drive file selected while disabled: " << path.value(); 89 callback.Run(base::FilePath()); 90 return; 91 } 92 file_system->GetFileForSaving(drive::util::ExtractDrivePath(path), 93 base::Bind(&OnDriveGetFile, path, callback)); 94 return; 95 } 96 97 // TODO(kinaba): For now, the only writable non-local volume is Drive. 98 NOTREACHED(); 99 callback.Run(base::FilePath()); 100 } 101 102 // Forward declarations of helper functions for GetSelectedFileInfo(). 103 void ContinueGetSelectedFileInfo(Profile* profile, 104 scoped_ptr<GetSelectedFileInfoParams> params, 105 const base::FilePath& local_file_path); 106 107 // Part of GetSelectedFileInfo(). 108 void GetSelectedFileInfoInternal(Profile* profile, 109 scoped_ptr<GetSelectedFileInfoParams> params) { 110 DCHECK(profile); 111 112 for (size_t i = params->selected_files.size(); 113 i < params->file_paths.size(); ++i) { 114 const base::FilePath& file_path = params->file_paths[i]; 115 116 if (file_manager::util::IsUnderNonNativeLocalPath(profile, file_path)) { 117 // When the caller of the select file dialog wants local file paths, and 118 // the selected path does not point to a native local path (e.g., Drive, 119 // MTP, or provided file system), we should resolve the path. 120 switch (params->local_path_option) { 121 case NO_LOCAL_PATH_RESOLUTION: 122 break; // No special handling needed. 123 case NEED_LOCAL_PATH_FOR_OPENING: 124 GetFileNativeLocalPathForOpening( 125 profile, 126 file_path, 127 base::Bind(&ContinueGetSelectedFileInfo, 128 profile, 129 base::Passed(¶ms))); 130 return; // Remaining work is done in ContinueGetSelectedFileInfo. 131 case NEED_LOCAL_PATH_FOR_SAVING: 132 GetFileNativeLocalPathForSaving( 133 profile, 134 file_path, 135 base::Bind(&ContinueGetSelectedFileInfo, 136 profile, 137 base::Passed(¶ms))); 138 return; // Remaining work is done in ContinueGetSelectedFileInfo. 139 } 140 } 141 params->selected_files.push_back( 142 ui::SelectedFileInfo(file_path, base::FilePath())); 143 } 144 params->callback.Run(params->selected_files); 145 } 146 147 // Part of GetSelectedFileInfo(). 148 void ContinueGetSelectedFileInfo(Profile* profile, 149 scoped_ptr<GetSelectedFileInfoParams> params, 150 const base::FilePath& local_path) { 151 if (local_path.empty()) { 152 params->callback.Run(std::vector<ui::SelectedFileInfo>()); 153 return; 154 } 155 const int index = params->selected_files.size(); 156 const base::FilePath& file_path = params->file_paths[index]; 157 params->selected_files.push_back(ui::SelectedFileInfo(file_path, local_path)); 158 GetSelectedFileInfoInternal(profile, params.Pass()); 159 } 160 161 } // namespace 162 163 void VolumeInfoToVolumeMetadata( 164 Profile* profile, 165 const VolumeInfo& volume_info, 166 file_manager_private::VolumeMetadata* volume_metadata) { 167 DCHECK(volume_metadata); 168 169 volume_metadata->volume_id = volume_info.volume_id; 170 171 // TODO(kinaba): fill appropriate information once multi-profile support is 172 // implemented. 173 volume_metadata->profile.display_name = profile->GetProfileName(); 174 volume_metadata->profile.is_current_profile = true; 175 176 if (!volume_info.source_path.empty()) { 177 volume_metadata->source_path.reset( 178 new std::string(volume_info.source_path.AsUTF8Unsafe())); 179 } 180 181 if (volume_info.type == VOLUME_TYPE_PROVIDED) { 182 volume_metadata->extension_id.reset( 183 new std::string(volume_info.extension_id)); 184 185 volume_metadata->file_system_id.reset( 186 new std::string(volume_info.file_system_id)); 187 } 188 189 volume_metadata->volume_label.reset( 190 new std::string(volume_info.volume_label)); 191 192 switch (volume_info.type) { 193 case VOLUME_TYPE_GOOGLE_DRIVE: 194 volume_metadata->volume_type = 195 file_manager_private::VOLUME_TYPE_DRIVE; 196 break; 197 case VOLUME_TYPE_DOWNLOADS_DIRECTORY: 198 volume_metadata->volume_type = 199 file_manager_private::VOLUME_TYPE_DOWNLOADS; 200 break; 201 case VOLUME_TYPE_REMOVABLE_DISK_PARTITION: 202 volume_metadata->volume_type = 203 file_manager_private::VOLUME_TYPE_REMOVABLE; 204 break; 205 case VOLUME_TYPE_MOUNTED_ARCHIVE_FILE: 206 volume_metadata->volume_type = file_manager_private::VOLUME_TYPE_ARCHIVE; 207 break; 208 case VOLUME_TYPE_CLOUD_DEVICE: 209 volume_metadata->volume_type = 210 file_manager_private::VOLUME_TYPE_CLOUD_DEVICE; 211 break; 212 case VOLUME_TYPE_PROVIDED: 213 volume_metadata->volume_type = file_manager_private::VOLUME_TYPE_PROVIDED; 214 break; 215 case VOLUME_TYPE_MTP: 216 volume_metadata->volume_type = file_manager_private::VOLUME_TYPE_MTP; 217 break; 218 case VOLUME_TYPE_TESTING: 219 volume_metadata->volume_type = 220 file_manager_private::VOLUME_TYPE_TESTING; 221 break; 222 case NUM_VOLUME_TYPE: 223 NOTREACHED(); 224 break; 225 } 226 227 // Fill device_type iff the volume is removable partition. 228 if (volume_info.type == VOLUME_TYPE_REMOVABLE_DISK_PARTITION) { 229 switch (volume_info.device_type) { 230 case chromeos::DEVICE_TYPE_UNKNOWN: 231 volume_metadata->device_type = 232 file_manager_private::DEVICE_TYPE_UNKNOWN; 233 break; 234 case chromeos::DEVICE_TYPE_USB: 235 volume_metadata->device_type = file_manager_private::DEVICE_TYPE_USB; 236 break; 237 case chromeos::DEVICE_TYPE_SD: 238 volume_metadata->device_type = file_manager_private::DEVICE_TYPE_SD; 239 break; 240 case chromeos::DEVICE_TYPE_OPTICAL_DISC: 241 case chromeos::DEVICE_TYPE_DVD: 242 volume_metadata->device_type = 243 file_manager_private::DEVICE_TYPE_OPTICAL; 244 break; 245 case chromeos::DEVICE_TYPE_MOBILE: 246 volume_metadata->device_type = file_manager_private::DEVICE_TYPE_MOBILE; 247 break; 248 } 249 volume_metadata->device_path.reset( 250 new std::string(volume_info.system_path_prefix.AsUTF8Unsafe())); 251 volume_metadata->is_parent_device.reset( 252 new bool(volume_info.is_parent)); 253 } else { 254 volume_metadata->device_type = 255 file_manager_private::DEVICE_TYPE_NONE; 256 } 257 258 volume_metadata->is_read_only = volume_info.is_read_only; 259 260 switch (volume_info.mount_condition) { 261 case chromeos::disks::MOUNT_CONDITION_NONE: 262 volume_metadata->mount_condition = 263 file_manager_private::MOUNT_CONDITION_NONE; 264 break; 265 case chromeos::disks::MOUNT_CONDITION_UNKNOWN_FILESYSTEM: 266 volume_metadata->mount_condition = 267 file_manager_private::MOUNT_CONDITION_UNKNOWN; 268 break; 269 case chromeos::disks::MOUNT_CONDITION_UNSUPPORTED_FILESYSTEM: 270 volume_metadata->mount_condition = 271 file_manager_private::MOUNT_CONDITION_UNSUPPORTED; 272 break; 273 } 274 } 275 276 base::FilePath GetLocalPathFromURL(content::RenderViewHost* render_view_host, 277 Profile* profile, 278 const GURL& url) { 279 DCHECK(render_view_host); 280 DCHECK(profile); 281 282 scoped_refptr<storage::FileSystemContext> file_system_context = 283 util::GetFileSystemContextForRenderViewHost(profile, render_view_host); 284 285 const storage::FileSystemURL filesystem_url( 286 file_system_context->CrackURL(url)); 287 base::FilePath path; 288 if (!chromeos::FileSystemBackend::CanHandleURL(filesystem_url)) 289 return base::FilePath(); 290 return filesystem_url.path(); 291 } 292 293 void GetSelectedFileInfo(content::RenderViewHost* render_view_host, 294 Profile* profile, 295 const std::vector<GURL>& file_urls, 296 GetSelectedFileInfoLocalPathOption local_path_option, 297 GetSelectedFileInfoCallback callback) { 298 DCHECK(render_view_host); 299 DCHECK(profile); 300 301 scoped_ptr<GetSelectedFileInfoParams> params(new GetSelectedFileInfoParams); 302 params->local_path_option = local_path_option; 303 params->callback = callback; 304 305 for (size_t i = 0; i < file_urls.size(); ++i) { 306 const GURL& file_url = file_urls[i]; 307 const base::FilePath path = GetLocalPathFromURL( 308 render_view_host, profile, file_url); 309 if (!path.empty()) { 310 DVLOG(1) << "Selected: file path: " << path.value(); 311 params->file_paths.push_back(path); 312 } 313 } 314 315 base::MessageLoop::current()->PostTask( 316 FROM_HERE, 317 base::Bind(&GetSelectedFileInfoInternal, profile, base::Passed(¶ms))); 318 } 319 320 void SetupProfileFileAccessPermissions(int render_view_process_id, 321 Profile* profile) { 322 const base::FilePath paths[] = { 323 drive::util::GetDriveMountPointPath(profile), 324 util::GetDownloadsFolderForProfile(profile), 325 }; 326 for (size_t i = 0; i < arraysize(paths); ++i) { 327 content::ChildProcessSecurityPolicy::GetInstance( 328 )->GrantCreateReadWriteFile(render_view_process_id, paths[i]); 329 } 330 } 331 332 drive::EventLogger* GetLogger(Profile* profile) { 333 drive::DriveIntegrationService* service = 334 drive::DriveIntegrationServiceFactory::FindForProfile(profile); 335 return service ? service->event_logger() : NULL; 336 } 337 338 } // namespace util 339 } // namespace file_manager 340