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_browser_private.h" 25 #include "content/public/browser/child_process_security_policy.h" 26 #include "ui/shell_dialogs/selected_file_info.h" 27 #include "webkit/browser/fileapi/file_system_context.h" 28 #include "webkit/browser/fileapi/file_system_url.h" 29 30 namespace file_browser_private = extensions::api::file_browser_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 const int index = params->selected_files.size(); 152 const base::FilePath& file_path = params->file_paths[index]; 153 params->selected_files.push_back(ui::SelectedFileInfo(file_path, local_path)); 154 GetSelectedFileInfoInternal(profile, params.Pass()); 155 } 156 157 } // namespace 158 159 void VolumeInfoToVolumeMetadata( 160 Profile* profile, 161 const VolumeInfo& volume_info, 162 file_browser_private::VolumeMetadata* volume_metadata) { 163 DCHECK(volume_metadata); 164 165 volume_metadata->volume_id = volume_info.volume_id; 166 167 // TODO(kinaba): fill appropriate information once multi-profile support is 168 // implemented. 169 volume_metadata->profile.display_name = profile->GetProfileName(); 170 volume_metadata->profile.is_current_profile = true; 171 172 if (!volume_info.source_path.empty()) { 173 volume_metadata->source_path.reset( 174 new std::string(volume_info.source_path.AsUTF8Unsafe())); 175 } 176 177 if (volume_info.type == VOLUME_TYPE_PROVIDED) { 178 volume_metadata->extension_id.reset( 179 new std::string(volume_info.extension_id)); 180 181 volume_metadata->file_system_id.reset( 182 new std::string(volume_info.file_system_id)); 183 } 184 185 volume_metadata->volume_label.reset( 186 new std::string(volume_info.volume_label)); 187 188 switch (volume_info.type) { 189 case VOLUME_TYPE_GOOGLE_DRIVE: 190 volume_metadata->volume_type = 191 file_browser_private::VOLUME_TYPE_DRIVE; 192 break; 193 case VOLUME_TYPE_DOWNLOADS_DIRECTORY: 194 volume_metadata->volume_type = 195 file_browser_private::VOLUME_TYPE_DOWNLOADS; 196 break; 197 case VOLUME_TYPE_REMOVABLE_DISK_PARTITION: 198 volume_metadata->volume_type = 199 file_browser_private::VOLUME_TYPE_REMOVABLE; 200 break; 201 case VOLUME_TYPE_MOUNTED_ARCHIVE_FILE: 202 volume_metadata->volume_type = file_browser_private::VOLUME_TYPE_ARCHIVE; 203 break; 204 case VOLUME_TYPE_CLOUD_DEVICE: 205 volume_metadata->volume_type = 206 file_browser_private::VOLUME_TYPE_CLOUD_DEVICE; 207 break; 208 case VOLUME_TYPE_PROVIDED: 209 volume_metadata->volume_type = file_browser_private::VOLUME_TYPE_PROVIDED; 210 break; 211 case VOLUME_TYPE_MTP: 212 volume_metadata->volume_type = file_browser_private::VOLUME_TYPE_MTP; 213 break; 214 case VOLUME_TYPE_TESTING: 215 volume_metadata->volume_type = 216 file_browser_private::VOLUME_TYPE_TESTING; 217 break; 218 case NUM_VOLUME_TYPE: 219 NOTREACHED(); 220 break; 221 } 222 223 // Fill device_type iff the volume is removable partition. 224 if (volume_info.type == VOLUME_TYPE_REMOVABLE_DISK_PARTITION) { 225 switch (volume_info.device_type) { 226 case chromeos::DEVICE_TYPE_UNKNOWN: 227 volume_metadata->device_type = 228 file_browser_private::DEVICE_TYPE_UNKNOWN; 229 break; 230 case chromeos::DEVICE_TYPE_USB: 231 volume_metadata->device_type = file_browser_private::DEVICE_TYPE_USB; 232 break; 233 case chromeos::DEVICE_TYPE_SD: 234 volume_metadata->device_type = file_browser_private::DEVICE_TYPE_SD; 235 break; 236 case chromeos::DEVICE_TYPE_OPTICAL_DISC: 237 case chromeos::DEVICE_TYPE_DVD: 238 volume_metadata->device_type = 239 file_browser_private::DEVICE_TYPE_OPTICAL; 240 break; 241 case chromeos::DEVICE_TYPE_MOBILE: 242 volume_metadata->device_type = file_browser_private::DEVICE_TYPE_MOBILE; 243 break; 244 } 245 volume_metadata->device_path.reset( 246 new std::string(volume_info.system_path_prefix.AsUTF8Unsafe())); 247 volume_metadata->is_parent_device.reset( 248 new bool(volume_info.is_parent)); 249 } else { 250 volume_metadata->device_type = 251 file_browser_private::DEVICE_TYPE_NONE; 252 } 253 254 volume_metadata->is_read_only = volume_info.is_read_only; 255 256 switch (volume_info.mount_condition) { 257 case chromeos::disks::MOUNT_CONDITION_NONE: 258 volume_metadata->mount_condition = 259 file_browser_private::MOUNT_CONDITION_NONE; 260 break; 261 case chromeos::disks::MOUNT_CONDITION_UNKNOWN_FILESYSTEM: 262 volume_metadata->mount_condition = 263 file_browser_private::MOUNT_CONDITION_UNKNOWN; 264 break; 265 case chromeos::disks::MOUNT_CONDITION_UNSUPPORTED_FILESYSTEM: 266 volume_metadata->mount_condition = 267 file_browser_private::MOUNT_CONDITION_UNSUPPORTED; 268 break; 269 } 270 } 271 272 base::FilePath GetLocalPathFromURL(content::RenderViewHost* render_view_host, 273 Profile* profile, 274 const GURL& url) { 275 DCHECK(render_view_host); 276 DCHECK(profile); 277 278 scoped_refptr<fileapi::FileSystemContext> file_system_context = 279 util::GetFileSystemContextForRenderViewHost(profile, render_view_host); 280 281 const fileapi::FileSystemURL filesystem_url( 282 file_system_context->CrackURL(url)); 283 base::FilePath path; 284 if (!chromeos::FileSystemBackend::CanHandleURL(filesystem_url)) 285 return base::FilePath(); 286 return filesystem_url.path(); 287 } 288 289 void GetSelectedFileInfo(content::RenderViewHost* render_view_host, 290 Profile* profile, 291 const std::vector<GURL>& file_urls, 292 GetSelectedFileInfoLocalPathOption local_path_option, 293 GetSelectedFileInfoCallback callback) { 294 DCHECK(render_view_host); 295 DCHECK(profile); 296 297 scoped_ptr<GetSelectedFileInfoParams> params(new GetSelectedFileInfoParams); 298 params->local_path_option = local_path_option; 299 params->callback = callback; 300 301 for (size_t i = 0; i < file_urls.size(); ++i) { 302 const GURL& file_url = file_urls[i]; 303 const base::FilePath path = GetLocalPathFromURL( 304 render_view_host, profile, file_url); 305 if (!path.empty()) { 306 DVLOG(1) << "Selected: file path: " << path.value(); 307 params->file_paths.push_back(path); 308 } 309 } 310 311 base::MessageLoop::current()->PostTask( 312 FROM_HERE, 313 base::Bind(&GetSelectedFileInfoInternal, profile, base::Passed(¶ms))); 314 } 315 316 void SetupProfileFileAccessPermissions(int render_view_process_id, 317 Profile* profile) { 318 const base::FilePath paths[] = { 319 drive::util::GetDriveMountPointPath(profile), 320 util::GetDownloadsFolderForProfile(profile), 321 }; 322 for (size_t i = 0; i < arraysize(paths); ++i) { 323 content::ChildProcessSecurityPolicy::GetInstance( 324 )->GrantCreateReadWriteFile(render_view_process_id, paths[i]); 325 } 326 } 327 328 drive::EventLogger* GetLogger(Profile* profile) { 329 drive::DriveIntegrationService* service = 330 drive::DriveIntegrationServiceFactory::FindForProfileRegardlessOfStates( 331 profile); 332 return service ? service->event_logger() : NULL; 333 } 334 335 } // namespace util 336 } // namespace file_manager 337