| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/browser/extensions/api/file_system/file_system_api.h" | 5 #include "extensions/browser/api/file_system/file_system_api.h" |
| 6 | 6 |
| 7 #include <stddef.h> | 7 #include <stddef.h> |
| 8 | 8 |
| 9 #include <memory> | 9 #include <memory> |
| 10 #include <set> | 10 #include <set> |
| 11 #include <utility> | 11 #include <utility> |
| 12 #include <vector> | 12 #include <vector> |
| 13 | 13 |
| 14 #include "apps/saved_files_service.h" | |
| 15 #include "base/bind.h" | 14 #include "base/bind.h" |
| 16 #include "base/callback.h" | |
| 17 #include "base/files/file_path.h" | 15 #include "base/files/file_path.h" |
| 18 #include "base/files/file_util.h" | 16 #include "base/files/file_util.h" |
| 19 #include "base/macros.h" | 17 #include "base/macros.h" |
| 20 #include "base/memory/ptr_util.h" | 18 #include "base/memory/ptr_util.h" |
| 19 #include "base/memory/ref_counted.h" |
| 20 #include "base/memory/weak_ptr.h" |
| 21 #include "base/path_service.h" | 21 #include "base/path_service.h" |
| 22 #include "base/stl_util.h" | 22 #include "base/stl_util.h" |
| 23 #include "base/strings/string16.h" |
| 23 #include "base/strings/string_util.h" | 24 #include "base/strings/string_util.h" |
| 24 #include "base/strings/stringprintf.h" | 25 #include "base/strings/stringprintf.h" |
| 25 #include "base/strings/sys_string_conversions.h" | |
| 26 #include "base/strings/utf_string_conversions.h" | 26 #include "base/strings/utf_string_conversions.h" |
| 27 #include "base/task_scheduler/post_task.h" | 27 #include "base/task_scheduler/post_task.h" |
| 28 #include "base/value_conversions.h" | 28 #include "base/value_conversions.h" |
| 29 #include "base/values.h" | 29 #include "base/values.h" |
| 30 #include "build/build_config.h" | 30 #include "build/build_config.h" |
| 31 #include "chrome/browser/extensions/api/file_system/file_entry_picker.h" | 31 #include "content/public/browser/browser_context.h" |
| 32 #include "chrome/browser/platform_util.h" | |
| 33 #include "chrome/browser/profiles/profile.h" | |
| 34 #include "chrome/browser/ui/apps/directory_access_confirmation_dialog.h" | |
| 35 #include "chrome/browser/ui/chrome_select_file_policy.h" | |
| 36 #include "chrome/common/chrome_paths.h" | |
| 37 #include "chrome/common/extensions/api/file_system.h" | |
| 38 #include "chrome/grit/generated_resources.h" | |
| 39 #include "content/public/browser/browser_thread.h" | 32 #include "content/public/browser/browser_thread.h" |
| 40 #include "content/public/browser/child_process_security_policy.h" | 33 #include "content/public/browser/child_process_security_policy.h" |
| 41 #include "content/public/browser/render_frame_host.h" | 34 #include "content/public/browser/render_frame_host.h" |
| 42 #include "content/public/browser/render_process_host.h" | 35 #include "content/public/browser/render_process_host.h" |
| 43 #include "content/public/browser/storage_partition.h" | 36 #include "content/public/browser/storage_partition.h" |
| 44 #include "content/public/browser/web_contents.h" | 37 #include "content/public/browser/web_contents.h" |
| 38 #include "extensions/browser/api/extensions_api_client.h" |
| 45 #include "extensions/browser/api/file_handlers/app_file_handler_util.h" | 39 #include "extensions/browser/api/file_handlers/app_file_handler_util.h" |
| 40 #include "extensions/browser/api/file_system/file_system_delegate.h" |
| 46 #include "extensions/browser/api/file_system/saved_file_entry.h" | 41 #include "extensions/browser/api/file_system/saved_file_entry.h" |
| 42 #include "extensions/browser/api/file_system/saved_files_service_interface.h" |
| 47 #include "extensions/browser/app_window/app_window.h" | 43 #include "extensions/browser/app_window/app_window.h" |
| 48 #include "extensions/browser/app_window/app_window_registry.h" | 44 #include "extensions/browser/app_window/app_window_registry.h" |
| 49 #include "extensions/browser/extension_prefs.h" | 45 #include "extensions/browser/extension_prefs.h" |
| 50 #include "extensions/browser/extension_system.h" | |
| 51 #include "extensions/browser/extension_util.h" | 46 #include "extensions/browser/extension_util.h" |
| 52 #include "extensions/browser/granted_file_entry.h" | 47 #include "extensions/browser/granted_file_entry.h" |
| 53 #include "extensions/browser/path_util.h" | 48 #include "extensions/browser/path_util.h" |
| 49 #include "extensions/common/api/file_system.h" |
| 54 #include "extensions/common/permissions/api_permission.h" | 50 #include "extensions/common/permissions/api_permission.h" |
| 55 #include "extensions/common/permissions/permissions_data.h" | 51 #include "extensions/common/permissions/permissions_data.h" |
| 56 #include "net/base/mime_util.h" | 52 #include "net/base/mime_util.h" |
| 57 #include "storage/browser/fileapi/external_mount_points.h" | 53 #include "storage/browser/fileapi/external_mount_points.h" |
| 54 #include "storage/browser/fileapi/file_system_context.h" |
| 58 #include "storage/browser/fileapi/file_system_operation_runner.h" | 55 #include "storage/browser/fileapi/file_system_operation_runner.h" |
| 59 #include "storage/browser/fileapi/isolated_context.h" | 56 #include "storage/browser/fileapi/isolated_context.h" |
| 60 #include "storage/common/fileapi/file_system_types.h" | 57 #include "storage/common/fileapi/file_system_types.h" |
| 61 #include "storage/common/fileapi/file_system_util.h" | 58 #include "storage/common/fileapi/file_system_util.h" |
| 62 #include "ui/base/l10n/l10n_util.h" | 59 #include "ui/base/l10n/l10n_util.h" |
| 63 #include "ui/base/ui_base_types.h" | |
| 64 #include "ui/shell_dialogs/select_file_dialog.h" | 60 #include "ui/shell_dialogs/select_file_dialog.h" |
| 65 #include "ui/shell_dialogs/select_file_policy.h" | |
| 66 | 61 |
| 67 #if defined(OS_MACOSX) | 62 #if defined(OS_MACOSX) |
| 68 #include <CoreFoundation/CoreFoundation.h> | 63 #include <CoreFoundation/CoreFoundation.h> |
| 69 #include "base/mac/foundation_util.h" | 64 #include "base/mac/foundation_util.h" |
| 70 #endif | 65 #endif |
| 71 | 66 |
| 72 #if defined(OS_CHROMEOS) | 67 #if defined(OS_CHROMEOS) |
| 73 #include "base/strings/string16.h" | 68 #include "extensions/browser/api/file_handlers/non_native_file_system_delegate.h
" |
| 74 #include "chrome/browser/chromeos/file_manager/filesystem_api_util.h" | |
| 75 #include "chrome/browser/chromeos/file_manager/volume_manager.h" | |
| 76 #include "extensions/browser/event_router.h" | |
| 77 #include "extensions/browser/extension_registry.h" | |
| 78 #include "extensions/common/constants.h" | |
| 79 #include "url/url_constants.h" | |
| 80 #endif | 69 #endif |
| 81 | 70 |
| 82 using apps::SavedFilesService; | |
| 83 using storage::IsolatedContext; | 71 using storage::IsolatedContext; |
| 84 | 72 |
| 85 const char kInvalidCallingPage[] = | 73 const char kInvalidCallingPage[] = |
| 86 "Invalid calling page. " | 74 "Invalid calling page. " |
| 87 "This function can't be called from a background page."; | 75 "This function can't be called from a background page."; |
| 88 const char kUserCancelled[] = "User cancelled"; | 76 const char kUserCancelled[] = "User cancelled"; |
| 89 const char kWritableFileErrorFormat[] = "Error opening %s"; | 77 const char kWritableFileErrorFormat[] = "Error opening %s"; |
| 90 const char kRequiresFileSystemWriteError[] = | 78 const char kRequiresFileSystemWriteError[] = |
| 91 "Operation requires fileSystem.write permission"; | 79 "Operation requires fileSystem.write permission"; |
| 92 const char kRequiresFileSystemDirectoryError[] = | 80 const char kRequiresFileSystemDirectoryError[] = |
| 93 "Operation requires fileSystem.directory permission"; | 81 "Operation requires fileSystem.directory permission"; |
| 94 const char kMultipleUnsupportedError[] = | 82 const char kMultipleUnsupportedError[] = |
| 95 "acceptsMultiple: true is only supported for 'openFile'"; | 83 "acceptsMultiple: true is only supported for 'openFile'"; |
| 96 const char kUnknownIdError[] = "Unknown id"; | 84 const char kUnknownIdError[] = "Unknown id"; |
| 97 | |
| 98 #if !defined(OS_CHROMEOS) | |
| 99 const char kNotSupportedOnCurrentPlatformError[] = | 85 const char kNotSupportedOnCurrentPlatformError[] = |
| 100 "Operation not supported on the current platform."; | 86 "Operation not supported on the current platform."; |
| 101 #else | 87 const char kRetainEntryError[] = "Could not retain file entry."; |
| 88 |
| 89 #if defined(OS_CHROMEOS) |
| 102 const char kNotSupportedOnNonKioskSessionError[] = | 90 const char kNotSupportedOnNonKioskSessionError[] = |
| 103 "Operation only supported for kiosk apps running in a kiosk session."; | 91 "Operation only supported for kiosk apps running in a kiosk session."; |
| 104 const char kVolumeNotFoundError[] = "Volume not found."; | |
| 105 const char kSecurityError[] = "Security error."; | |
| 106 const char kConsentImpossible[] = | |
| 107 "Impossible to ask for user consent as there is no app window visible."; | |
| 108 #endif | 92 #endif |
| 109 | 93 |
| 110 namespace extensions { | 94 namespace extensions { |
| 111 | 95 |
| 112 namespace file_system = api::file_system; | 96 namespace file_system = api::file_system; |
| 113 namespace ChooseEntry = file_system::ChooseEntry; | 97 namespace ChooseEntry = file_system::ChooseEntry; |
| 114 | 98 |
| 115 namespace { | 99 namespace { |
| 116 | 100 |
| 117 bool g_skip_picker_for_test = false; | 101 bool g_skip_picker_for_test = false; |
| (...skipping 17 matching lines...) Expand all Loading... |
| 135 std::vector<std::string>* list = accept_option.mime_types.get(); | 119 std::vector<std::string>* list = accept_option.mime_types.get(); |
| 136 bool valid_type = false; | 120 bool valid_type = false; |
| 137 for (std::vector<std::string>::const_iterator iter = list->begin(); | 121 for (std::vector<std::string>::const_iterator iter = list->begin(); |
| 138 iter != list->end(); ++iter) { | 122 iter != list->end(); ++iter) { |
| 139 std::vector<base::FilePath::StringType> inner; | 123 std::vector<base::FilePath::StringType> inner; |
| 140 std::string accept_type = base::ToLowerASCII(*iter); | 124 std::string accept_type = base::ToLowerASCII(*iter); |
| 141 net::GetExtensionsForMimeType(accept_type, &inner); | 125 net::GetExtensionsForMimeType(accept_type, &inner); |
| 142 if (inner.empty()) | 126 if (inner.empty()) |
| 143 continue; | 127 continue; |
| 144 | 128 |
| 145 if (valid_type) | 129 if (valid_type) { |
| 146 description_id = 0; // We already have an accept type with label; if | 130 description_id = 0; // We already have an accept type with label; if |
| 147 // we find another, give up and use the default. | 131 // we find another, give up and use the default. |
| 148 else if (accept_type == "image/*") | 132 } else { |
| 149 description_id = IDS_IMAGE_FILES; | 133 FileSystemDelegate* delegate = |
| 150 else if (accept_type == "audio/*") | 134 ExtensionsAPIClient::Get()->GetFileSystemDelegate(); |
| 151 description_id = IDS_AUDIO_FILES; | 135 DCHECK(delegate); |
| 152 else if (accept_type == "video/*") | 136 description_id = delegate->GetDescriptionIdForAcceptType(accept_type); |
| 153 description_id = IDS_VIDEO_FILES; | 137 } |
| 154 | 138 |
| 155 extension_set.insert(inner.begin(), inner.end()); | 139 extension_set.insert(inner.begin(), inner.end()); |
| 156 valid_type = true; | 140 valid_type = true; |
| 157 } | 141 } |
| 158 } | 142 } |
| 159 | 143 |
| 160 if (accept_option.extensions.get()) { | 144 if (accept_option.extensions.get()) { |
| 161 std::vector<std::string>* list = accept_option.extensions.get(); | 145 std::vector<std::string>* list = accept_option.extensions.get(); |
| 162 for (std::vector<std::string>::const_iterator iter = list->begin(); | 146 for (std::vector<std::string>::const_iterator iter = list->begin(); |
| 163 iter != list->end(); ++iter) { | 147 iter != list->end(); ++iter) { |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 216 content::WebContents* web_contents = | 200 content::WebContents* web_contents = |
| 217 content::WebContents::FromRenderFrameHost(render_frame_host); | 201 content::WebContents::FromRenderFrameHost(render_frame_host); |
| 218 // Check if there is an app window associated with the web contents; if not, | 202 // Check if there is an app window associated with the web contents; if not, |
| 219 // return null. | 203 // return null. |
| 220 return AppWindowRegistry::Get(browser_context) | 204 return AppWindowRegistry::Get(browser_context) |
| 221 ->GetAppWindowForWebContents(web_contents) | 205 ->GetAppWindowForWebContents(web_contents) |
| 222 ? web_contents | 206 ? web_contents |
| 223 : nullptr; | 207 : nullptr; |
| 224 } | 208 } |
| 225 | 209 |
| 226 #if defined(OS_CHROMEOS) | |
| 227 // Fills a list of volumes mounted in the system. | |
| 228 void FillVolumeList(Profile* profile, | |
| 229 std::vector<api::file_system::Volume>* result) { | |
| 230 file_manager::VolumeManager* const volume_manager = | |
| 231 file_manager::VolumeManager::Get(profile); | |
| 232 DCHECK(volume_manager); | |
| 233 | |
| 234 const auto& volume_list = volume_manager->GetVolumeList(); | |
| 235 // Convert volume_list to result_volume_list. | |
| 236 for (const auto& volume : volume_list) { | |
| 237 api::file_system::Volume result_volume; | |
| 238 result_volume.volume_id = volume->volume_id(); | |
| 239 result_volume.writable = !volume->is_read_only(); | |
| 240 result->push_back(std::move(result_volume)); | |
| 241 } | |
| 242 } | |
| 243 #endif | |
| 244 | |
| 245 // Creates and shows a SelectFileDialog, or returns false if the dialog could | |
| 246 // not be created. | |
| 247 bool ShowSelectFileDialog( | |
| 248 scoped_refptr<UIThreadExtensionFunction> extension_function, | |
| 249 ui::SelectFileDialog::Type type, | |
| 250 const base::FilePath& default_path, | |
| 251 const ui::SelectFileDialog::FileTypeInfo* file_types, | |
| 252 FileEntryPicker::FilesSelectedCallback files_selected_callback, | |
| 253 base::OnceClosure file_selection_canceled_callback) { | |
| 254 // TODO(asargent/benwells) - As a short term remediation for | |
| 255 // crbug.com/179010 we're adding the ability for a whitelisted extension to | |
| 256 // use this API since chrome.fileBrowserHandler.selectFile is ChromeOS-only. | |
| 257 // Eventually we'd like a better solution and likely this code will go back | |
| 258 // to being platform-app only. | |
| 259 content::WebContents* const web_contents = | |
| 260 extension_function->extension()->is_platform_app() | |
| 261 ? GetWebContentsForRenderFrameHost( | |
| 262 extension_function->browser_context(), | |
| 263 extension_function->render_frame_host()) | |
| 264 : extension_function->GetAssociatedWebContents(); | |
| 265 if (!web_contents) | |
| 266 return false; | |
| 267 | |
| 268 // The file picker will hold a reference to the UIThreadExtensionFunction | |
| 269 // instance, preventing its destruction (and subsequent sending of the | |
| 270 // function response) until the user has selected a file or cancelled the | |
| 271 // picker. At that point, the picker will delete itself, which will also free | |
| 272 // the function instance. | |
| 273 new FileEntryPicker(web_contents, default_path, *file_types, type, | |
| 274 std::move(files_selected_callback), | |
| 275 std::move(file_selection_canceled_callback)); | |
| 276 return true; | |
| 277 } | |
| 278 | |
| 279 } // namespace | 210 } // namespace |
| 280 | 211 |
| 281 namespace file_system_api { | 212 namespace file_system_api { |
| 282 | 213 |
| 283 base::FilePath GetLastChooseEntryDirectory(const ExtensionPrefs* prefs, | 214 base::FilePath GetLastChooseEntryDirectory(const ExtensionPrefs* prefs, |
| 284 const std::string& extension_id) { | 215 const std::string& extension_id) { |
| 285 base::FilePath path; | 216 base::FilePath path; |
| 286 std::string string_path; | 217 std::string string_path; |
| 287 if (prefs->ReadPrefAsString(extension_id, kLastChooseEntryDirectory, | 218 if (prefs->ReadPrefAsString(extension_id, kLastChooseEntryDirectory, |
| 288 &string_path)) { | 219 &string_path)) { |
| 289 path = base::FilePath::FromUTF8Unsafe(string_path); | 220 path = base::FilePath::FromUTF8Unsafe(string_path); |
| 290 } | 221 } |
| 291 return path; | 222 return path; |
| 292 } | 223 } |
| 293 | 224 |
| 294 void SetLastChooseEntryDirectory(ExtensionPrefs* prefs, | 225 void SetLastChooseEntryDirectory(ExtensionPrefs* prefs, |
| 295 const std::string& extension_id, | 226 const std::string& extension_id, |
| 296 const base::FilePath& path) { | 227 const base::FilePath& path) { |
| 297 prefs->UpdateExtensionPref(extension_id, kLastChooseEntryDirectory, | 228 prefs->UpdateExtensionPref(extension_id, kLastChooseEntryDirectory, |
| 298 base::CreateFilePathValue(path)); | 229 base::CreateFilePathValue(path)); |
| 299 } | 230 } |
| 300 | 231 |
| 301 #if defined(OS_CHROMEOS) | |
| 302 void DispatchVolumeListChangeEvent(Profile* profile) { | |
| 303 DCHECK(profile); | |
| 304 EventRouter* const event_router = EventRouter::Get(profile); | |
| 305 if (!event_router) // Possible on shutdown. | |
| 306 return; | |
| 307 | |
| 308 ExtensionRegistry* const registry = ExtensionRegistry::Get(profile); | |
| 309 if (!registry) // Possible on shutdown. | |
| 310 return; | |
| 311 | |
| 312 ConsentProviderDelegate consent_provider_delegate(profile, nullptr); | |
| 313 ConsentProvider consent_provider(&consent_provider_delegate); | |
| 314 api::file_system::VolumeListChangedEvent event_args; | |
| 315 FillVolumeList(profile, &event_args.volumes); | |
| 316 for (const auto& extension : registry->enabled_extensions()) { | |
| 317 if (!consent_provider.IsGrantable(*extension.get())) | |
| 318 continue; | |
| 319 event_router->DispatchEventToExtension( | |
| 320 extension->id(), | |
| 321 base::MakeUnique<Event>( | |
| 322 events::FILE_SYSTEM_ON_VOLUME_LIST_CHANGED, | |
| 323 api::file_system::OnVolumeListChanged::kEventName, | |
| 324 api::file_system::OnVolumeListChanged::Create(event_args))); | |
| 325 } | |
| 326 } | |
| 327 #endif | |
| 328 | |
| 329 } // namespace file_system_api | 232 } // namespace file_system_api |
| 330 | 233 |
| 331 #if defined(OS_CHROMEOS) | |
| 332 using file_system_api::ConsentProvider; | |
| 333 #endif | |
| 334 | |
| 335 ExtensionFunction::ResponseAction FileSystemGetDisplayPathFunction::Run() { | 234 ExtensionFunction::ResponseAction FileSystemGetDisplayPathFunction::Run() { |
| 336 std::string filesystem_name; | 235 std::string filesystem_name; |
| 337 std::string filesystem_path; | 236 std::string filesystem_path; |
| 338 EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &filesystem_name)); | 237 EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &filesystem_name)); |
| 339 EXTENSION_FUNCTION_VALIDATE(args_->GetString(1, &filesystem_path)); | 238 EXTENSION_FUNCTION_VALIDATE(args_->GetString(1, &filesystem_path)); |
| 340 | 239 |
| 341 base::FilePath file_path; | 240 base::FilePath file_path; |
| 342 std::string error; | 241 std::string error; |
| 343 if (!app_file_handler_util::ValidateFileEntryAndGetPath( | 242 if (!app_file_handler_util::ValidateFileEntryAndGetPath( |
| 344 filesystem_name, filesystem_path, | 243 filesystem_name, filesystem_path, |
| (...skipping 13 matching lines...) Expand all Loading... |
| 358 const std::vector<base::FilePath>& paths) { | 257 const std::vector<base::FilePath>& paths) { |
| 359 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); | 258 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
| 360 // TODO(cmihail): Path directory set should be initialized only with the | 259 // TODO(cmihail): Path directory set should be initialized only with the |
| 361 // paths that are actually directories, but for now we will consider | 260 // paths that are actually directories, but for now we will consider |
| 362 // all paths directories in case is_directory_ is true, otherwise | 261 // all paths directories in case is_directory_ is true, otherwise |
| 363 // all paths files, as this was the previous logic. | 262 // all paths files, as this was the previous logic. |
| 364 std::set<base::FilePath> path_directory_set_ = | 263 std::set<base::FilePath> path_directory_set_ = |
| 365 is_directory_ ? std::set<base::FilePath>(paths.begin(), paths.end()) | 264 is_directory_ ? std::set<base::FilePath>(paths.begin(), paths.end()) |
| 366 : std::set<base::FilePath>{}; | 265 : std::set<base::FilePath>{}; |
| 367 app_file_handler_util::PrepareFilesForWritableApp( | 266 app_file_handler_util::PrepareFilesForWritableApp( |
| 368 paths, GetProfile(), path_directory_set_, | 267 paths, browser_context(), path_directory_set_, |
| 369 base::Bind(&FileSystemEntryFunction::RegisterFileSystemsAndSendResponse, | 268 base::Bind(&FileSystemEntryFunction::RegisterFileSystemsAndSendResponse, |
| 370 this, paths), | 269 this, paths), |
| 371 base::Bind(&FileSystemEntryFunction::HandleWritableFileError, this)); | 270 base::Bind(&FileSystemEntryFunction::HandleWritableFileError, this)); |
| 372 } | 271 } |
| 373 | 272 |
| 374 void FileSystemEntryFunction::RegisterFileSystemsAndSendResponse( | 273 void FileSystemEntryFunction::RegisterFileSystemsAndSendResponse( |
| 375 const std::vector<base::FilePath>& paths) { | 274 const std::vector<base::FilePath>& paths) { |
| 376 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); | 275 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
| 377 if (!render_frame_host()) | 276 if (!render_frame_host()) |
| 378 return; | 277 return; |
| 379 | 278 |
| 380 std::unique_ptr<base::DictionaryValue> result = CreateResult(); | 279 std::unique_ptr<base::DictionaryValue> result = CreateResult(); |
| 381 for (const auto& path : paths) | 280 for (const auto& path : paths) |
| 382 AddEntryToResult(path, std::string(), result.get()); | 281 AddEntryToResult(path, std::string(), result.get()); |
| 383 SetResult(std::move(result)); | 282 Respond(OneArgument(std::move(result))); |
| 384 SendResponse(true); | |
| 385 } | 283 } |
| 386 | 284 |
| 387 std::unique_ptr<base::DictionaryValue> FileSystemEntryFunction::CreateResult() { | 285 std::unique_ptr<base::DictionaryValue> FileSystemEntryFunction::CreateResult() { |
| 388 std::unique_ptr<base::DictionaryValue> result(new base::DictionaryValue()); | 286 std::unique_ptr<base::DictionaryValue> result(new base::DictionaryValue()); |
| 389 result->Set("entries", base::MakeUnique<base::ListValue>()); | 287 result->Set("entries", base::MakeUnique<base::ListValue>()); |
| 390 result->SetBoolean("multiple", multiple_); | 288 result->SetBoolean("multiple", multiple_); |
| 391 return result; | 289 return result; |
| 392 } | 290 } |
| 393 | 291 |
| 394 void FileSystemEntryFunction::AddEntryToResult(const base::FilePath& path, | 292 void FileSystemEntryFunction::AddEntryToResult(const base::FilePath& path, |
| 395 const std::string& id_override, | 293 const std::string& id_override, |
| 396 base::DictionaryValue* result) { | 294 base::DictionaryValue* result) { |
| 397 GrantedFileEntry file_entry = app_file_handler_util::CreateFileEntry( | 295 GrantedFileEntry file_entry = app_file_handler_util::CreateFileEntry( |
| 398 GetProfile(), extension(), render_frame_host()->GetProcess()->GetID(), | 296 browser_context(), extension(), |
| 399 path, is_directory_); | 297 render_frame_host()->GetProcess()->GetID(), path, is_directory_); |
| 400 base::ListValue* entries; | 298 base::ListValue* entries; |
| 401 bool success = result->GetList("entries", &entries); | 299 bool success = result->GetList("entries", &entries); |
| 402 DCHECK(success); | 300 DCHECK(success); |
| 403 | 301 |
| 404 std::unique_ptr<base::DictionaryValue> entry(new base::DictionaryValue()); | 302 std::unique_ptr<base::DictionaryValue> entry(new base::DictionaryValue()); |
| 405 entry->SetString("fileSystemId", file_entry.filesystem_id); | 303 entry->SetString("fileSystemId", file_entry.filesystem_id); |
| 406 entry->SetString("baseName", file_entry.registered_name); | 304 entry->SetString("baseName", file_entry.registered_name); |
| 407 if (id_override.empty()) | 305 if (id_override.empty()) |
| 408 entry->SetString("id", file_entry.id); | 306 entry->SetString("id", file_entry.id); |
| 409 else | 307 else |
| 410 entry->SetString("id", id_override); | 308 entry->SetString("id", id_override); |
| 411 entry->SetBoolean("isDirectory", is_directory_); | 309 entry->SetBoolean("isDirectory", is_directory_); |
| 412 entries->Append(std::move(entry)); | 310 entries->Append(std::move(entry)); |
| 413 } | 311 } |
| 414 | 312 |
| 415 void FileSystemEntryFunction::HandleWritableFileError( | 313 void FileSystemEntryFunction::HandleWritableFileError( |
| 416 const base::FilePath& error_path) { | 314 const base::FilePath& error_path) { |
| 417 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); | 315 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
| 418 error_ = base::StringPrintf(kWritableFileErrorFormat, | 316 Respond(Error(base::StringPrintf( |
| 419 error_path.BaseName().AsUTF8Unsafe().c_str()); | 317 kWritableFileErrorFormat, error_path.BaseName().AsUTF8Unsafe().c_str()))); |
| 420 SendResponse(false); | |
| 421 } | 318 } |
| 422 | 319 |
| 423 bool FileSystemGetWritableEntryFunction::RunAsync() { | 320 ExtensionFunction::ResponseAction FileSystemGetWritableEntryFunction::Run() { |
| 424 std::string filesystem_name; | 321 std::string filesystem_name; |
| 425 std::string filesystem_path; | 322 std::string filesystem_path; |
| 426 EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &filesystem_name)); | 323 EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &filesystem_name)); |
| 427 EXTENSION_FUNCTION_VALIDATE(args_->GetString(1, &filesystem_path)); | 324 EXTENSION_FUNCTION_VALIDATE(args_->GetString(1, &filesystem_path)); |
| 428 | 325 |
| 429 if (!app_file_handler_util::HasFileSystemWritePermission(extension_.get())) { | 326 if (!app_file_handler_util::HasFileSystemWritePermission(extension_.get())) { |
| 430 error_ = kRequiresFileSystemWriteError; | 327 return RespondNow(Error(kRequiresFileSystemWriteError)); |
| 431 return false; | |
| 432 } | 328 } |
| 433 | 329 |
| 330 std::string error; |
| 434 if (!app_file_handler_util::ValidateFileEntryAndGetPath( | 331 if (!app_file_handler_util::ValidateFileEntryAndGetPath( |
| 435 filesystem_name, filesystem_path, | 332 filesystem_name, filesystem_path, |
| 436 render_frame_host()->GetProcess()->GetID(), &path_, &error_)) | 333 render_frame_host()->GetProcess()->GetID(), &path_, &error)) { |
| 437 return false; | 334 return RespondNow(Error(error)); |
| 335 } |
| 438 | 336 |
| 439 base::PostTaskWithTraitsAndReply( | 337 base::PostTaskWithTraitsAndReply( |
| 440 FROM_HERE, {base::MayBlock(), base::TaskPriority::BACKGROUND}, | 338 FROM_HERE, {base::MayBlock(), base::TaskPriority::BACKGROUND}, |
| 441 base::BindOnce(&FileSystemGetWritableEntryFunction::SetIsDirectoryAsync, | 339 base::BindOnce(&FileSystemGetWritableEntryFunction::SetIsDirectoryAsync, |
| 442 this), | 340 this), |
| 443 base::BindOnce( | 341 base::BindOnce( |
| 444 &FileSystemGetWritableEntryFunction::CheckPermissionAndSendResponse, | 342 &FileSystemGetWritableEntryFunction::CheckPermissionAndSendResponse, |
| 445 this)); | 343 this)); |
| 446 return true; | 344 return RespondLater(); |
| 447 } | 345 } |
| 448 | 346 |
| 449 void FileSystemGetWritableEntryFunction::CheckPermissionAndSendResponse() { | 347 void FileSystemGetWritableEntryFunction::CheckPermissionAndSendResponse() { |
| 450 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); | 348 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
| 451 if (is_directory_ && !extension_->permissions_data()->HasAPIPermission( | 349 if (is_directory_ && !extension_->permissions_data()->HasAPIPermission( |
| 452 APIPermission::kFileSystemDirectory)) { | 350 APIPermission::kFileSystemDirectory)) { |
| 453 error_ = kRequiresFileSystemDirectoryError; | 351 Respond(Error(kRequiresFileSystemDirectoryError)); |
| 454 SendResponse(false); | 352 return; |
| 455 } | 353 } |
| 456 std::vector<base::FilePath> paths; | 354 std::vector<base::FilePath> paths; |
| 457 paths.push_back(path_); | 355 paths.push_back(path_); |
| 458 PrepareFilesForWritableApp(paths); | 356 PrepareFilesForWritableApp(paths); |
| 459 } | 357 } |
| 460 | 358 |
| 461 void FileSystemGetWritableEntryFunction::SetIsDirectoryAsync() { | 359 void FileSystemGetWritableEntryFunction::SetIsDirectoryAsync() { |
| 462 if (base::DirectoryExists(path_)) { | 360 if (base::DirectoryExists(path_)) { |
| 463 is_directory_ = true; | 361 is_directory_ = true; |
| 464 } | 362 } |
| (...skipping 13 matching lines...) Expand all Loading... |
| 478 content::ChildProcessSecurityPolicy::GetInstance(); | 376 content::ChildProcessSecurityPolicy::GetInstance(); |
| 479 int renderer_id = render_frame_host()->GetProcess()->GetID(); | 377 int renderer_id = render_frame_host()->GetProcess()->GetID(); |
| 480 bool is_writable = policy->CanReadWriteFileSystem(renderer_id, filesystem_id); | 378 bool is_writable = policy->CanReadWriteFileSystem(renderer_id, filesystem_id); |
| 481 | 379 |
| 482 return RespondNow(OneArgument(base::MakeUnique<base::Value>(is_writable))); | 380 return RespondNow(OneArgument(base::MakeUnique<base::Value>(is_writable))); |
| 483 } | 381 } |
| 484 | 382 |
| 485 void FileSystemChooseEntryFunction::ShowPicker( | 383 void FileSystemChooseEntryFunction::ShowPicker( |
| 486 const ui::SelectFileDialog::FileTypeInfo& file_type_info, | 384 const ui::SelectFileDialog::FileTypeInfo& file_type_info, |
| 487 ui::SelectFileDialog::Type picker_type) { | 385 ui::SelectFileDialog::Type picker_type) { |
| 386 // TODO(michaelpg): Use the FileSystemDelegate to override functionality for |
| 387 // tests instead of using global variables. |
| 488 if (g_skip_picker_for_test) { | 388 if (g_skip_picker_for_test) { |
| 489 std::vector<base::FilePath> test_paths; | 389 std::vector<base::FilePath> test_paths; |
| 490 if (g_use_suggested_path_for_test) | 390 if (g_use_suggested_path_for_test) |
| 491 test_paths.push_back(initial_path_); | 391 test_paths.push_back(initial_path_); |
| 492 else if (g_path_to_be_picked_for_test) | 392 else if (g_path_to_be_picked_for_test) |
| 493 test_paths.push_back(*g_path_to_be_picked_for_test); | 393 test_paths.push_back(*g_path_to_be_picked_for_test); |
| 494 else if (g_paths_to_be_picked_for_test) | 394 else if (g_paths_to_be_picked_for_test) |
| 495 test_paths = *g_paths_to_be_picked_for_test; | 395 test_paths = *g_paths_to_be_picked_for_test; |
| 496 | 396 |
| 497 content::BrowserThread::PostTask( | 397 content::BrowserThread::PostTask( |
| 498 content::BrowserThread::UI, FROM_HERE, | 398 content::BrowserThread::UI, FROM_HERE, |
| 499 test_paths.size() > 0 | 399 test_paths.size() > 0 |
| 500 ? base::BindOnce(&FileSystemChooseEntryFunction::FilesSelected, | 400 ? base::BindOnce(&FileSystemChooseEntryFunction::FilesSelected, |
| 501 this, test_paths) | 401 this, test_paths) |
| 502 : base::BindOnce( | 402 : base::BindOnce( |
| 503 &FileSystemChooseEntryFunction::FileSelectionCanceled, this)); | 403 &FileSystemChooseEntryFunction::FileSelectionCanceled, this)); |
| 504 return; | 404 return; |
| 505 } | 405 } |
| 506 | 406 |
| 407 FileSystemDelegate* delegate = |
| 408 ExtensionsAPIClient::Get()->GetFileSystemDelegate(); |
| 409 DCHECK(delegate); |
| 410 |
| 507 // The callbacks passed to the dialog will retain references to this | 411 // The callbacks passed to the dialog will retain references to this |
| 508 // UIThreadExtenisonFunction, preventing its destruction (and subsequent | 412 // UIThreadExtenisonFunction, preventing its destruction (and subsequent |
| 509 // sending of the function response) until the user has selected a file or | 413 // sending of the function response) until the user has selected a file or |
| 510 // cancelled the picker. | 414 // cancelled the picker. |
| 511 if (!ShowSelectFileDialog( | 415 if (!delegate->ShowSelectFileDialog( |
| 512 this, picker_type, initial_path_, &file_type_info, | 416 this, picker_type, initial_path_, &file_type_info, |
| 513 base::BindOnce(&FileSystemChooseEntryFunction::FilesSelected, this), | 417 base::BindOnce(&FileSystemChooseEntryFunction::FilesSelected, this), |
| 514 base::BindOnce(&FileSystemChooseEntryFunction::FileSelectionCanceled, | 418 base::BindOnce(&FileSystemChooseEntryFunction::FileSelectionCanceled, |
| 515 this))) { | 419 this))) { |
| 516 error_ = kInvalidCallingPage; | 420 Respond(Error(kInvalidCallingPage)); |
| 517 SendResponse(false); | |
| 518 } | 421 } |
| 519 } | 422 } |
| 520 | 423 |
| 521 // static | 424 // static |
| 522 void FileSystemChooseEntryFunction::SkipPickerAndAlwaysSelectPathForTest( | 425 void FileSystemChooseEntryFunction::SkipPickerAndAlwaysSelectPathForTest( |
| 523 base::FilePath* path) { | 426 base::FilePath* path) { |
| 524 g_skip_picker_for_test = true; | 427 g_skip_picker_for_test = true; |
| 525 g_use_suggested_path_for_test = false; | 428 g_use_suggested_path_for_test = false; |
| 526 g_path_to_be_picked_for_test = path; | 429 g_path_to_be_picked_for_test = path; |
| 527 g_paths_to_be_picked_for_test = NULL; | 430 g_paths_to_be_picked_for_test = NULL; |
| 528 } | 431 } |
| 529 | 432 |
| 433 // static |
| 530 void FileSystemChooseEntryFunction::SkipPickerAndAlwaysSelectPathsForTest( | 434 void FileSystemChooseEntryFunction::SkipPickerAndAlwaysSelectPathsForTest( |
| 531 std::vector<base::FilePath>* paths) { | 435 std::vector<base::FilePath>* paths) { |
| 532 g_skip_picker_for_test = true; | 436 g_skip_picker_for_test = true; |
| 533 g_use_suggested_path_for_test = false; | 437 g_use_suggested_path_for_test = false; |
| 534 g_paths_to_be_picked_for_test = paths; | 438 g_paths_to_be_picked_for_test = paths; |
| 535 } | 439 } |
| 536 | 440 |
| 537 // static | 441 // static |
| 538 void FileSystemChooseEntryFunction::SkipPickerAndSelectSuggestedPathForTest() { | 442 void FileSystemChooseEntryFunction::SkipPickerAndSelectSuggestedPathForTest() { |
| 539 g_skip_picker_for_test = true; | 443 g_skip_picker_for_test = true; |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 587 void FileSystemChooseEntryFunction::FilesSelected( | 491 void FileSystemChooseEntryFunction::FilesSelected( |
| 588 const std::vector<base::FilePath>& paths) { | 492 const std::vector<base::FilePath>& paths) { |
| 589 DCHECK(!paths.empty()); | 493 DCHECK(!paths.empty()); |
| 590 base::FilePath last_choose_directory; | 494 base::FilePath last_choose_directory; |
| 591 if (is_directory_) { | 495 if (is_directory_) { |
| 592 last_choose_directory = paths[0]; | 496 last_choose_directory = paths[0]; |
| 593 } else { | 497 } else { |
| 594 last_choose_directory = paths[0].DirName(); | 498 last_choose_directory = paths[0].DirName(); |
| 595 } | 499 } |
| 596 file_system_api::SetLastChooseEntryDirectory( | 500 file_system_api::SetLastChooseEntryDirectory( |
| 597 ExtensionPrefs::Get(GetProfile()), extension()->id(), | 501 ExtensionPrefs::Get(browser_context()), extension()->id(), |
| 598 last_choose_directory); | 502 last_choose_directory); |
| 599 if (is_directory_) { | 503 if (is_directory_) { |
| 600 // Get the WebContents for the app window to be the parent window of the | 504 // Get the WebContents for the app window to be the parent window of the |
| 601 // confirmation dialog if necessary. | 505 // confirmation dialog if necessary. |
| 602 content::WebContents* const web_contents = | 506 content::WebContents* const web_contents = GetWebContentsForRenderFrameHost( |
| 603 GetWebContentsForRenderFrameHost(GetProfile(), render_frame_host()); | 507 browser_context(), render_frame_host()); |
| 604 if (!web_contents) { | 508 if (!web_contents) { |
| 605 error_ = kInvalidCallingPage; | 509 Respond(Error(kInvalidCallingPage)); |
| 606 SendResponse(false); | |
| 607 return; | 510 return; |
| 608 } | 511 } |
| 609 | 512 |
| 610 DCHECK_EQ(paths.size(), 1u); | 513 DCHECK_EQ(paths.size(), 1u); |
| 611 bool non_native_path = false; | 514 bool non_native_path = false; |
| 612 #if defined(OS_CHROMEOS) | 515 #if defined(OS_CHROMEOS) |
| 613 non_native_path = | 516 NonNativeFileSystemDelegate* delegate = |
| 614 file_manager::util::IsUnderNonNativeLocalPath(GetProfile(), paths[0]); | 517 ExtensionsAPIClient::Get()->GetNonNativeFileSystemDelegate(); |
| 518 non_native_path = delegate && delegate->IsUnderNonNativeLocalPath( |
| 519 browser_context(), paths[0]); |
| 615 #endif | 520 #endif |
| 616 | 521 |
| 617 base::PostTaskWithTraits( | 522 base::PostTaskWithTraits( |
| 618 FROM_HERE, {base::MayBlock(), base::TaskPriority::BACKGROUND}, | 523 FROM_HERE, {base::MayBlock(), base::TaskPriority::BACKGROUND}, |
| 619 base::BindOnce( | 524 base::BindOnce( |
| 620 &FileSystemChooseEntryFunction::ConfirmDirectoryAccessAsync, this, | 525 &FileSystemChooseEntryFunction::ConfirmDirectoryAccessAsync, this, |
| 621 non_native_path, paths, web_contents)); | 526 non_native_path, paths, web_contents)); |
| 622 return; | 527 return; |
| 623 } | 528 } |
| 624 | 529 |
| 625 OnDirectoryAccessConfirmed(paths); | 530 OnDirectoryAccessConfirmed(paths); |
| 626 } | 531 } |
| 627 | 532 |
| 628 void FileSystemChooseEntryFunction::FileSelectionCanceled() { | 533 void FileSystemChooseEntryFunction::FileSelectionCanceled() { |
| 629 error_ = kUserCancelled; | 534 Respond(Error(kUserCancelled)); |
| 630 SendResponse(false); | |
| 631 } | 535 } |
| 632 | 536 |
| 633 void FileSystemChooseEntryFunction::ConfirmDirectoryAccessAsync( | 537 void FileSystemChooseEntryFunction::ConfirmDirectoryAccessAsync( |
| 634 bool non_native_path, | 538 bool non_native_path, |
| 635 const std::vector<base::FilePath>& paths, | 539 const std::vector<base::FilePath>& paths, |
| 636 content::WebContents* web_contents) { | 540 content::WebContents* web_contents) { |
| 637 const base::FilePath check_path = | 541 const base::FilePath check_path = |
| 638 non_native_path ? paths[0] : base::MakeAbsoluteFilePath(paths[0]); | 542 non_native_path ? paths[0] : base::MakeAbsoluteFilePath(paths[0]); |
| 639 if (check_path.empty()) { | 543 if (check_path.empty()) { |
| 640 content::BrowserThread::PostTask( | 544 content::BrowserThread::PostTask( |
| 641 content::BrowserThread::UI, FROM_HERE, | 545 content::BrowserThread::UI, FROM_HERE, |
| 642 base::BindOnce(&FileSystemChooseEntryFunction::FileSelectionCanceled, | 546 base::BindOnce(&FileSystemChooseEntryFunction::FileSelectionCanceled, |
| 643 this)); | 547 this)); |
| 644 return; | 548 return; |
| 645 } | 549 } |
| 646 | 550 |
| 647 for (size_t i = 0; i < arraysize(kGraylistedPaths); i++) { | 551 for (size_t i = 0; i < arraysize(kGraylistedPaths); i++) { |
| 648 base::FilePath graylisted_path; | 552 base::FilePath graylisted_path; |
| 649 if (PathService::Get(kGraylistedPaths[i], &graylisted_path) && | 553 if (!PathService::Get(kGraylistedPaths[i], &graylisted_path)) |
| 650 (check_path == graylisted_path || | 554 continue; |
| 651 check_path.IsParent(graylisted_path))) { | 555 if (check_path != graylisted_path && !check_path.IsParent(graylisted_path)) |
| 652 if (g_skip_directory_confirmation_for_test) { | 556 continue; |
| 653 if (g_allow_directory_access_for_test) { | |
| 654 break; | |
| 655 } else { | |
| 656 content::BrowserThread::PostTask( | |
| 657 content::BrowserThread::UI, FROM_HERE, | |
| 658 base::BindOnce( | |
| 659 &FileSystemChooseEntryFunction::FileSelectionCanceled, this)); | |
| 660 } | |
| 661 return; | |
| 662 } | |
| 663 | 557 |
| 558 if (g_skip_directory_confirmation_for_test) { |
| 559 if (g_allow_directory_access_for_test) |
| 560 break; |
| 664 content::BrowserThread::PostTask( | 561 content::BrowserThread::PostTask( |
| 665 content::BrowserThread::UI, FROM_HERE, | 562 content::BrowserThread::UI, FROM_HERE, |
| 666 base::BindOnce( | 563 base::BindOnce(&FileSystemChooseEntryFunction::FileSelectionCanceled, |
| 667 CreateDirectoryAccessConfirmationDialog, | 564 this)); |
| 668 app_file_handler_util::HasFileSystemWritePermission( | |
| 669 extension_.get()), | |
| 670 base::UTF8ToUTF16(extension_->name()), web_contents, | |
| 671 base::Bind( | |
| 672 &FileSystemChooseEntryFunction::OnDirectoryAccessConfirmed, | |
| 673 this, paths), | |
| 674 base::Bind(&FileSystemChooseEntryFunction::FileSelectionCanceled, | |
| 675 this))); | |
| 676 return; | 565 return; |
| 677 } | 566 } |
| 567 |
| 568 content::BrowserThread::PostTask( |
| 569 content::BrowserThread::UI, FROM_HERE, |
| 570 base::BindOnce( |
| 571 &FileSystemChooseEntryFunction::ConfirmSensitiveDirectoryAccess, |
| 572 this, paths, web_contents)); |
| 573 return; |
| 678 } | 574 } |
| 679 | 575 |
| 680 content::BrowserThread::PostTask( | 576 content::BrowserThread::PostTask( |
| 681 content::BrowserThread::UI, FROM_HERE, | 577 content::BrowserThread::UI, FROM_HERE, |
| 682 base::BindOnce(&FileSystemChooseEntryFunction::OnDirectoryAccessConfirmed, | 578 base::BindOnce(&FileSystemChooseEntryFunction::OnDirectoryAccessConfirmed, |
| 683 this, paths)); | 579 this, paths)); |
| 684 } | 580 } |
| 685 | 581 |
| 582 void FileSystemChooseEntryFunction::ConfirmSensitiveDirectoryAccess( |
| 583 const std::vector<base::FilePath>& paths, |
| 584 content::WebContents* web_contents) { |
| 585 if (ExtensionsBrowserClient::Get()->IsShuttingDown()) { |
| 586 FileSelectionCanceled(); |
| 587 return; |
| 588 } |
| 589 |
| 590 FileSystemDelegate* delegate = |
| 591 ExtensionsAPIClient::Get()->GetFileSystemDelegate(); |
| 592 if (!delegate) { |
| 593 Respond(Error(kNotSupportedOnCurrentPlatformError)); |
| 594 return; |
| 595 } |
| 596 |
| 597 delegate->ConfirmSensitiveDirectoryAccess( |
| 598 app_file_handler_util::HasFileSystemWritePermission(extension_.get()), |
| 599 base::UTF8ToUTF16(extension_->name()), web_contents, |
| 600 base::Bind(&FileSystemChooseEntryFunction::OnDirectoryAccessConfirmed, |
| 601 this, paths), |
| 602 base::Bind(&FileSystemChooseEntryFunction::FileSelectionCanceled, this)); |
| 603 } |
| 604 |
| 686 void FileSystemChooseEntryFunction::OnDirectoryAccessConfirmed( | 605 void FileSystemChooseEntryFunction::OnDirectoryAccessConfirmed( |
| 687 const std::vector<base::FilePath>& paths) { | 606 const std::vector<base::FilePath>& paths) { |
| 688 if (app_file_handler_util::HasFileSystemWritePermission(extension_.get())) { | 607 if (app_file_handler_util::HasFileSystemWritePermission(extension_.get())) { |
| 689 PrepareFilesForWritableApp(paths); | 608 PrepareFilesForWritableApp(paths); |
| 690 return; | 609 return; |
| 691 } | 610 } |
| 692 | 611 |
| 693 // Don't need to check the file, it's for reading. | 612 // Don't need to check the file, it's for reading. |
| 694 RegisterFileSystemsAndSendResponse(paths); | 613 RegisterFileSystemsAndSendResponse(paths); |
| 695 } | 614 } |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 755 void FileSystemChooseEntryFunction::SetInitialPathAndShowPicker( | 674 void FileSystemChooseEntryFunction::SetInitialPathAndShowPicker( |
| 756 const base::FilePath& previous_path, | 675 const base::FilePath& previous_path, |
| 757 const base::FilePath& suggested_name, | 676 const base::FilePath& suggested_name, |
| 758 const ui::SelectFileDialog::FileTypeInfo& file_type_info, | 677 const ui::SelectFileDialog::FileTypeInfo& file_type_info, |
| 759 ui::SelectFileDialog::Type picker_type, | 678 ui::SelectFileDialog::Type picker_type, |
| 760 bool is_previous_path_directory) { | 679 bool is_previous_path_directory) { |
| 761 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); | 680 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
| 762 if (is_previous_path_directory) { | 681 if (is_previous_path_directory) { |
| 763 initial_path_ = previous_path.Append(suggested_name); | 682 initial_path_ = previous_path.Append(suggested_name); |
| 764 } else { | 683 } else { |
| 765 base::FilePath documents_dir; | 684 FileSystemDelegate* delegate = |
| 766 if (PathService::Get(chrome::DIR_USER_DOCUMENTS, &documents_dir)) { | 685 ExtensionsAPIClient::Get()->GetFileSystemDelegate(); |
| 767 initial_path_ = documents_dir.Append(suggested_name); | 686 DCHECK(delegate); |
| 768 } else { | 687 const base::FilePath default_directory = delegate->GetDefaultDirectory(); |
| 688 if (!default_directory.empty()) |
| 689 initial_path_ = default_directory.Append(suggested_name); |
| 690 else |
| 769 initial_path_ = suggested_name; | 691 initial_path_ = suggested_name; |
| 770 } | |
| 771 } | 692 } |
| 772 ShowPicker(file_type_info, picker_type); | 693 ShowPicker(file_type_info, picker_type); |
| 773 } | 694 } |
| 774 | 695 |
| 775 bool FileSystemChooseEntryFunction::RunAsync() { | 696 ExtensionFunction::ResponseAction FileSystemChooseEntryFunction::Run() { |
| 776 std::unique_ptr<ChooseEntry::Params> params( | 697 std::unique_ptr<ChooseEntry::Params> params( |
| 777 ChooseEntry::Params::Create(*args_)); | 698 ChooseEntry::Params::Create(*args_)); |
| 778 EXTENSION_FUNCTION_VALIDATE(params.get()); | 699 EXTENSION_FUNCTION_VALIDATE(params.get()); |
| 779 | 700 |
| 780 base::FilePath suggested_name; | 701 base::FilePath suggested_name; |
| 781 ui::SelectFileDialog::FileTypeInfo file_type_info; | 702 ui::SelectFileDialog::FileTypeInfo file_type_info; |
| 782 ui::SelectFileDialog::Type picker_type = | 703 ui::SelectFileDialog::Type picker_type = |
| 783 ui::SelectFileDialog::SELECT_OPEN_FILE; | 704 ui::SelectFileDialog::SELECT_OPEN_FILE; |
| 784 | 705 |
| 785 file_system::ChooseEntryOptions* options = params->options.get(); | 706 file_system::ChooseEntryOptions* options = params->options.get(); |
| 786 if (options) { | 707 if (options) { |
| 787 multiple_ = options->accepts_multiple && *options->accepts_multiple; | 708 multiple_ = options->accepts_multiple && *options->accepts_multiple; |
| 788 if (multiple_) | 709 if (multiple_) |
| 789 picker_type = ui::SelectFileDialog::SELECT_OPEN_MULTI_FILE; | 710 picker_type = ui::SelectFileDialog::SELECT_OPEN_MULTI_FILE; |
| 790 | 711 |
| 791 if (options->type == file_system::CHOOSE_ENTRY_TYPE_OPENWRITABLEFILE && | 712 if (options->type == file_system::CHOOSE_ENTRY_TYPE_OPENWRITABLEFILE && |
| 792 !app_file_handler_util::HasFileSystemWritePermission( | 713 !app_file_handler_util::HasFileSystemWritePermission( |
| 793 extension_.get())) { | 714 extension_.get())) { |
| 794 error_ = kRequiresFileSystemWriteError; | 715 return RespondNow(Error(kRequiresFileSystemWriteError)); |
| 795 return false; | |
| 796 } else if (options->type == file_system::CHOOSE_ENTRY_TYPE_SAVEFILE) { | 716 } else if (options->type == file_system::CHOOSE_ENTRY_TYPE_SAVEFILE) { |
| 797 if (!app_file_handler_util::HasFileSystemWritePermission( | 717 if (!app_file_handler_util::HasFileSystemWritePermission( |
| 798 extension_.get())) { | 718 extension_.get())) { |
| 799 error_ = kRequiresFileSystemWriteError; | 719 return RespondNow(Error(kRequiresFileSystemWriteError)); |
| 800 return false; | |
| 801 } | 720 } |
| 802 if (multiple_) { | 721 if (multiple_) { |
| 803 error_ = kMultipleUnsupportedError; | 722 return RespondNow(Error(kMultipleUnsupportedError)); |
| 804 return false; | |
| 805 } | 723 } |
| 806 picker_type = ui::SelectFileDialog::SELECT_SAVEAS_FILE; | 724 picker_type = ui::SelectFileDialog::SELECT_SAVEAS_FILE; |
| 807 } else if (options->type == file_system::CHOOSE_ENTRY_TYPE_OPENDIRECTORY) { | 725 } else if (options->type == file_system::CHOOSE_ENTRY_TYPE_OPENDIRECTORY) { |
| 808 is_directory_ = true; | 726 is_directory_ = true; |
| 809 if (!extension_->permissions_data()->HasAPIPermission( | 727 if (!extension_->permissions_data()->HasAPIPermission( |
| 810 APIPermission::kFileSystemDirectory)) { | 728 APIPermission::kFileSystemDirectory)) { |
| 811 error_ = kRequiresFileSystemDirectoryError; | 729 return RespondNow(Error(kRequiresFileSystemDirectoryError)); |
| 812 return false; | |
| 813 } | 730 } |
| 814 if (multiple_) { | 731 if (multiple_) { |
| 815 error_ = kMultipleUnsupportedError; | 732 return RespondNow(Error(kMultipleUnsupportedError)); |
| 816 return false; | |
| 817 } | 733 } |
| 818 picker_type = ui::SelectFileDialog::SELECT_FOLDER; | 734 picker_type = ui::SelectFileDialog::SELECT_FOLDER; |
| 819 } | 735 } |
| 820 | 736 |
| 821 base::FilePath::StringType suggested_extension; | 737 base::FilePath::StringType suggested_extension; |
| 822 BuildSuggestion(options->suggested_name.get(), &suggested_name, | 738 BuildSuggestion(options->suggested_name.get(), &suggested_name, |
| 823 &suggested_extension); | 739 &suggested_extension); |
| 824 | 740 |
| 825 BuildFileTypeInfo(&file_type_info, suggested_extension, | 741 BuildFileTypeInfo(&file_type_info, suggested_extension, |
| 826 options->accepts.get(), options->accepts_all_types.get()); | 742 options->accepts.get(), options->accepts_all_types.get()); |
| 827 } | 743 } |
| 828 | 744 |
| 829 file_type_info.allowed_paths = ui::SelectFileDialog::FileTypeInfo::ANY_PATH; | 745 file_type_info.allowed_paths = ui::SelectFileDialog::FileTypeInfo::ANY_PATH; |
| 830 | 746 |
| 831 base::FilePath previous_path = file_system_api::GetLastChooseEntryDirectory( | 747 base::FilePath previous_path = file_system_api::GetLastChooseEntryDirectory( |
| 832 ExtensionPrefs::Get(GetProfile()), extension()->id()); | 748 ExtensionPrefs::Get(browser_context()), extension()->id()); |
| 833 | 749 |
| 834 if (previous_path.empty()) { | 750 if (previous_path.empty()) { |
| 835 SetInitialPathAndShowPicker(previous_path, suggested_name, file_type_info, | 751 SetInitialPathAndShowPicker(previous_path, suggested_name, file_type_info, |
| 836 picker_type, false); | 752 picker_type, false); |
| 837 return true; | 753 return RespondLater(); |
| 838 } | 754 } |
| 839 | 755 |
| 840 base::Callback<void(bool)> set_initial_path_callback = base::Bind( | 756 base::Callback<void(bool)> set_initial_path_callback = base::Bind( |
| 841 &FileSystemChooseEntryFunction::SetInitialPathAndShowPicker, this, | 757 &FileSystemChooseEntryFunction::SetInitialPathAndShowPicker, this, |
| 842 previous_path, suggested_name, file_type_info, picker_type); | 758 previous_path, suggested_name, file_type_info, picker_type); |
| 843 | 759 |
| 844 // Check whether the |previous_path| is a non-native directory. | 760 // Check whether the |previous_path| is a non-native directory. |
| 845 #if defined(OS_CHROMEOS) | 761 #if defined(OS_CHROMEOS) |
| 846 if (file_manager::util::IsUnderNonNativeLocalPath(GetProfile(), | 762 NonNativeFileSystemDelegate* delegate = |
| 847 previous_path)) { | 763 ExtensionsAPIClient::Get()->GetNonNativeFileSystemDelegate(); |
| 848 file_manager::util::IsNonNativeLocalPathDirectory( | 764 if (delegate && |
| 849 GetProfile(), previous_path, set_initial_path_callback); | 765 delegate->IsUnderNonNativeLocalPath(browser_context(), previous_path)) { |
| 850 return true; | 766 delegate->IsNonNativeLocalPathDirectory(browser_context(), previous_path, |
| 767 set_initial_path_callback); |
| 768 return RespondLater(); |
| 851 } | 769 } |
| 852 #endif | 770 #endif |
| 853 base::PostTaskWithTraitsAndReplyWithResult( | 771 base::PostTaskWithTraitsAndReplyWithResult( |
| 854 FROM_HERE, {base::MayBlock(), base::TaskPriority::BACKGROUND}, | 772 FROM_HERE, {base::MayBlock(), base::TaskPriority::BACKGROUND}, |
| 855 base::Bind(&base::DirectoryExists, previous_path), | 773 base::Bind(&base::DirectoryExists, previous_path), |
| 856 set_initial_path_callback); | 774 set_initial_path_callback); |
| 857 | 775 |
| 858 return true; | 776 return RespondLater(); |
| 859 } | 777 } |
| 860 | 778 |
| 861 bool FileSystemRetainEntryFunction::RunAsync() { | 779 ExtensionFunction::ResponseAction FileSystemRetainEntryFunction::Run() { |
| 862 std::string entry_id; | 780 std::string entry_id; |
| 863 EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &entry_id)); | 781 EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &entry_id)); |
| 864 SavedFilesService* saved_files_service = SavedFilesService::Get(GetProfile()); | 782 |
| 783 FileSystemDelegate* delegate = |
| 784 ExtensionsAPIClient::Get()->GetFileSystemDelegate(); |
| 785 DCHECK(delegate); |
| 786 |
| 787 SavedFilesServiceInterface* saved_files_service = |
| 788 delegate->GetSavedFilesService(browser_context()); |
| 789 DCHECK(saved_files_service); |
| 790 |
| 865 // Add the file to the retain list if it is not already on there. | 791 // Add the file to the retain list if it is not already on there. |
| 866 if (!saved_files_service->IsRegistered(extension_->id(), entry_id)) { | 792 if (!saved_files_service->IsRegistered(extension_->id(), entry_id)) { |
| 867 std::string filesystem_name; | 793 std::string filesystem_name; |
| 868 std::string filesystem_path; | 794 std::string filesystem_path; |
| 869 base::FilePath path; | 795 base::FilePath path; |
| 870 EXTENSION_FUNCTION_VALIDATE(args_->GetString(1, &filesystem_name)); | 796 EXTENSION_FUNCTION_VALIDATE(args_->GetString(1, &filesystem_name)); |
| 871 EXTENSION_FUNCTION_VALIDATE(args_->GetString(2, &filesystem_path)); | 797 EXTENSION_FUNCTION_VALIDATE(args_->GetString(2, &filesystem_path)); |
| 798 std::string error; |
| 872 if (!app_file_handler_util::ValidateFileEntryAndGetPath( | 799 if (!app_file_handler_util::ValidateFileEntryAndGetPath( |
| 873 filesystem_name, filesystem_path, | 800 filesystem_name, filesystem_path, |
| 874 render_frame_host()->GetProcess()->GetID(), &path, &error_)) { | 801 render_frame_host()->GetProcess()->GetID(), &path, &error)) { |
| 875 return false; | 802 return RespondNow(Error(error)); |
| 876 } | 803 } |
| 877 | 804 |
| 878 std::string filesystem_id; | 805 std::string filesystem_id; |
| 879 if (!storage::CrackIsolatedFileSystemName(filesystem_name, &filesystem_id)) | 806 if (!storage::CrackIsolatedFileSystemName(filesystem_name, &filesystem_id)) |
| 880 return false; | 807 return RespondNow(Error(kRetainEntryError)); |
| 881 | 808 |
| 882 const GURL site = util::GetSiteForExtensionId(extension_id(), GetProfile()); | 809 const GURL site = |
| 810 util::GetSiteForExtensionId(extension_id(), browser_context()); |
| 883 storage::FileSystemContext* const context = | 811 storage::FileSystemContext* const context = |
| 884 content::BrowserContext::GetStoragePartitionForSite(GetProfile(), site) | 812 content::BrowserContext::GetStoragePartitionForSite(browser_context(), |
| 813 site) |
| 885 ->GetFileSystemContext(); | 814 ->GetFileSystemContext(); |
| 886 const storage::FileSystemURL url = context->CreateCrackedFileSystemURL( | 815 const storage::FileSystemURL url = context->CreateCrackedFileSystemURL( |
| 887 site, storage::kFileSystemTypeIsolated, | 816 site, storage::kFileSystemTypeIsolated, |
| 888 IsolatedContext::GetInstance() | 817 storage::IsolatedContext::GetInstance() |
| 889 ->CreateVirtualRootPath(filesystem_id) | 818 ->CreateVirtualRootPath(filesystem_id) |
| 890 .Append(base::FilePath::FromUTF8Unsafe(filesystem_path))); | 819 .Append(base::FilePath::FromUTF8Unsafe(filesystem_path))); |
| 891 | 820 |
| 892 content::BrowserThread::PostTask( | 821 content::BrowserThread::PostTask( |
| 893 content::BrowserThread::IO, FROM_HERE, | 822 content::BrowserThread::IO, FROM_HERE, |
| 894 base::BindOnce( | 823 base::BindOnce( |
| 895 base::IgnoreResult( | 824 base::IgnoreResult( |
| 896 &storage::FileSystemOperationRunner::GetMetadata), | 825 &storage::FileSystemOperationRunner::GetMetadata), |
| 897 context->operation_runner()->AsWeakPtr(), url, | 826 context->operation_runner()->AsWeakPtr(), url, |
| 898 storage::FileSystemOperation::GET_METADATA_FIELD_IS_DIRECTORY, | 827 storage::FileSystemOperation::GET_METADATA_FIELD_IS_DIRECTORY, |
| 899 base::Bind( | 828 base::Bind( |
| 900 &PassFileInfoToUIThread, | 829 &PassFileInfoToUIThread, |
| 901 base::Bind(&FileSystemRetainEntryFunction::RetainFileEntry, | 830 base::Bind(&FileSystemRetainEntryFunction::RetainFileEntry, |
| 902 this, entry_id, path)))); | 831 this, entry_id, path)))); |
| 903 return true; | 832 return RespondLater(); |
| 904 } | 833 } |
| 905 | 834 |
| 906 saved_files_service->EnqueueFileEntry(extension_->id(), entry_id); | 835 saved_files_service->EnqueueFileEntry(extension_->id(), entry_id); |
| 907 SendResponse(true); | 836 return RespondNow(NoArguments()); |
| 908 return true; | |
| 909 } | 837 } |
| 910 | 838 |
| 911 void FileSystemRetainEntryFunction::RetainFileEntry( | 839 void FileSystemRetainEntryFunction::RetainFileEntry( |
| 912 const std::string& entry_id, | 840 const std::string& entry_id, |
| 913 const base::FilePath& path, | 841 const base::FilePath& path, |
| 914 std::unique_ptr<base::File::Info> file_info) { | 842 std::unique_ptr<base::File::Info> file_info) { |
| 915 if (!file_info) { | 843 if (!file_info) { |
| 916 SendResponse(false); | 844 Respond(Error(kRetainEntryError)); |
| 917 return; | 845 return; |
| 918 } | 846 } |
| 919 | 847 |
| 920 SavedFilesService* saved_files_service = SavedFilesService::Get(GetProfile()); | 848 FileSystemDelegate* delegate = |
| 849 ExtensionsAPIClient::Get()->GetFileSystemDelegate(); |
| 850 DCHECK(delegate); |
| 851 |
| 852 SavedFilesServiceInterface* saved_files_service = |
| 853 delegate->GetSavedFilesService(browser_context()); |
| 854 DCHECK(saved_files_service); |
| 921 saved_files_service->RegisterFileEntry(extension_->id(), entry_id, path, | 855 saved_files_service->RegisterFileEntry(extension_->id(), entry_id, path, |
| 922 file_info->is_directory); | 856 file_info->is_directory); |
| 923 saved_files_service->EnqueueFileEntry(extension_->id(), entry_id); | 857 saved_files_service->EnqueueFileEntry(extension_->id(), entry_id); |
| 924 SendResponse(true); | 858 Respond(NoArguments()); |
| 925 } | 859 } |
| 926 | 860 |
| 927 ExtensionFunction::ResponseAction FileSystemIsRestorableFunction::Run() { | 861 ExtensionFunction::ResponseAction FileSystemIsRestorableFunction::Run() { |
| 928 std::string entry_id; | 862 std::string entry_id; |
| 929 EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &entry_id)); | 863 EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &entry_id)); |
| 864 |
| 865 FileSystemDelegate* delegate = |
| 866 ExtensionsAPIClient::Get()->GetFileSystemDelegate(); |
| 867 DCHECK(delegate); |
| 868 |
| 869 SavedFilesServiceInterface* saved_files_service = |
| 870 delegate->GetSavedFilesService(browser_context()); |
| 871 DCHECK(saved_files_service); |
| 872 |
| 930 return RespondNow(OneArgument(base::MakeUnique<base::Value>( | 873 return RespondNow(OneArgument(base::MakeUnique<base::Value>( |
| 931 SavedFilesService::Get(Profile::FromBrowserContext(browser_context())) | 874 saved_files_service->IsRegistered(extension_->id(), entry_id)))); |
| 932 ->IsRegistered(extension_->id(), entry_id)))); | |
| 933 } | 875 } |
| 934 | 876 |
| 935 bool FileSystemRestoreEntryFunction::RunAsync() { | 877 ExtensionFunction::ResponseAction FileSystemRestoreEntryFunction::Run() { |
| 936 std::string entry_id; | 878 std::string entry_id; |
| 937 bool needs_new_entry; | 879 bool needs_new_entry; |
| 938 EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &entry_id)); | 880 EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &entry_id)); |
| 939 EXTENSION_FUNCTION_VALIDATE(args_->GetBoolean(1, &needs_new_entry)); | 881 EXTENSION_FUNCTION_VALIDATE(args_->GetBoolean(1, &needs_new_entry)); |
| 940 const SavedFileEntry* file_entry = | 882 FileSystemDelegate* delegate = |
| 941 SavedFilesService::Get(GetProfile()) | 883 ExtensionsAPIClient::Get()->GetFileSystemDelegate(); |
| 942 ->GetFileEntry(extension_->id(), entry_id); | 884 DCHECK(delegate); |
| 943 if (!file_entry) { | |
| 944 error_ = kUnknownIdError; | |
| 945 return false; | |
| 946 } | |
| 947 | 885 |
| 948 SavedFilesService::Get(GetProfile()) | 886 SavedFilesServiceInterface* saved_files_service = |
| 949 ->EnqueueFileEntry(extension_->id(), entry_id); | 887 delegate->GetSavedFilesService(browser_context()); |
| 888 DCHECK(saved_files_service); |
| 889 const SavedFileEntry* file = |
| 890 saved_files_service->GetFileEntry(extension_->id(), entry_id); |
| 891 if (!file) |
| 892 return RespondNow(Error(kUnknownIdError)); |
| 893 |
| 894 saved_files_service->EnqueueFileEntry(extension_->id(), entry_id); |
| 950 | 895 |
| 951 // Only create a new file entry if the renderer requests one. | 896 // Only create a new file entry if the renderer requests one. |
| 952 // |needs_new_entry| will be false if the renderer already has an Entry for | 897 // |needs_new_entry| will be false if the renderer already has an Entry for |
| 953 // |entry_id|. | 898 // |entry_id|. |
| 954 if (needs_new_entry) { | 899 if (needs_new_entry) { |
| 955 is_directory_ = file_entry->is_directory; | 900 is_directory_ = file->is_directory; |
| 956 std::unique_ptr<base::DictionaryValue> result = CreateResult(); | 901 std::unique_ptr<base::DictionaryValue> result = CreateResult(); |
| 957 AddEntryToResult(file_entry->path, file_entry->id, result.get()); | 902 AddEntryToResult(file->path, file->id, result.get()); |
| 958 SetResult(std::move(result)); | 903 return RespondNow(OneArgument(std::move(result))); |
| 959 } | 904 } |
| 960 SendResponse(true); | 905 return RespondNow(NoArguments()); |
| 961 return true; | |
| 962 } | 906 } |
| 963 | 907 |
| 964 ExtensionFunction::ResponseAction FileSystemObserveDirectoryFunction::Run() { | 908 ExtensionFunction::ResponseAction FileSystemObserveDirectoryFunction::Run() { |
| 965 NOTIMPLEMENTED(); | 909 NOTIMPLEMENTED(); |
| 966 return RespondNow(Error(kUnknownIdError)); | 910 return RespondNow(Error(kUnknownIdError)); |
| 967 } | 911 } |
| 968 | 912 |
| 969 ExtensionFunction::ResponseAction FileSystemUnobserveEntryFunction::Run() { | 913 ExtensionFunction::ResponseAction FileSystemUnobserveEntryFunction::Run() { |
| 970 NOTIMPLEMENTED(); | 914 NOTIMPLEMENTED(); |
| 971 return RespondNow(Error(kUnknownIdError)); | 915 return RespondNow(Error(kUnknownIdError)); |
| 972 } | 916 } |
| 973 | 917 |
| 974 ExtensionFunction::ResponseAction FileSystemGetObservedEntriesFunction::Run() { | 918 ExtensionFunction::ResponseAction FileSystemGetObservedEntriesFunction::Run() { |
| 975 NOTIMPLEMENTED(); | 919 NOTIMPLEMENTED(); |
| 976 return RespondNow(Error(kUnknownIdError)); | 920 return RespondNow(Error(kUnknownIdError)); |
| 977 } | 921 } |
| 978 | 922 |
| 979 #if !defined(OS_CHROMEOS) | 923 #if !defined(OS_CHROMEOS) |
| 980 ExtensionFunction::ResponseAction FileSystemRequestFileSystemFunction::Run() { | 924 ExtensionFunction::ResponseAction FileSystemRequestFileSystemFunction::Run() { |
| 981 using api::file_system::RequestFileSystem::Params; | 925 using file_system::RequestFileSystem::Params; |
| 982 const std::unique_ptr<Params> params(Params::Create(*args_)); | 926 const std::unique_ptr<Params> params(Params::Create(*args_)); |
| 983 EXTENSION_FUNCTION_VALIDATE(params); | 927 EXTENSION_FUNCTION_VALIDATE(params); |
| 984 | 928 |
| 985 NOTIMPLEMENTED(); | 929 NOTIMPLEMENTED(); |
| 986 return RespondNow(Error(kNotSupportedOnCurrentPlatformError)); | 930 return RespondNow(Error(kNotSupportedOnCurrentPlatformError)); |
| 987 } | 931 } |
| 988 | 932 |
| 989 ExtensionFunction::ResponseAction FileSystemGetVolumeListFunction::Run() { | 933 ExtensionFunction::ResponseAction FileSystemGetVolumeListFunction::Run() { |
| 990 NOTIMPLEMENTED(); | 934 NOTIMPLEMENTED(); |
| 991 return RespondNow(Error(kNotSupportedOnCurrentPlatformError)); | 935 return RespondNow(Error(kNotSupportedOnCurrentPlatformError)); |
| 992 } | 936 } |
| 993 #else | 937 #else |
| 994 | 938 |
| 995 FileSystemRequestFileSystemFunction::FileSystemRequestFileSystemFunction() | 939 FileSystemRequestFileSystemFunction::FileSystemRequestFileSystemFunction() {} |
| 996 : chrome_details_(this) {} | |
| 997 | 940 |
| 998 FileSystemRequestFileSystemFunction::~FileSystemRequestFileSystemFunction() {} | 941 FileSystemRequestFileSystemFunction::~FileSystemRequestFileSystemFunction() {} |
| 999 | 942 |
| 1000 ExtensionFunction::ResponseAction FileSystemRequestFileSystemFunction::Run() { | 943 ExtensionFunction::ResponseAction FileSystemRequestFileSystemFunction::Run() { |
| 1001 using api::file_system::RequestFileSystem::Params; | 944 using file_system::RequestFileSystem::Params; |
| 1002 const std::unique_ptr<Params> params(Params::Create(*args_)); | 945 const std::unique_ptr<Params> params(Params::Create(*args_)); |
| 1003 EXTENSION_FUNCTION_VALIDATE(params); | 946 EXTENSION_FUNCTION_VALIDATE(params); |
| 1004 | 947 |
| 948 FileSystemDelegate* delegate = |
| 949 ExtensionsAPIClient::Get()->GetFileSystemDelegate(); |
| 950 DCHECK(delegate); |
| 1005 // Only kiosk apps in kiosk sessions can use this API. | 951 // Only kiosk apps in kiosk sessions can use this API. |
| 1006 // Additionally it is enabled for whitelisted component extensions and apps. | 952 // Additionally it is enabled for whitelisted component extensions and apps. |
| 1007 file_system_api::ConsentProviderDelegate consent_provider_delegate( | 953 if (!delegate->IsGrantable(browser_context(), render_frame_host(), |
| 1008 chrome_details_.GetProfile(), render_frame_host()); | 954 *extension())) { |
| 1009 file_system_api::ConsentProvider consent_provider(&consent_provider_delegate); | |
| 1010 | |
| 1011 if (!consent_provider.IsGrantable(*extension())) | |
| 1012 return RespondNow(Error(kNotSupportedOnNonKioskSessionError)); | 955 return RespondNow(Error(kNotSupportedOnNonKioskSessionError)); |
| 1013 | |
| 1014 using file_manager::VolumeManager; | |
| 1015 using file_manager::Volume; | |
| 1016 VolumeManager* const volume_manager = | |
| 1017 VolumeManager::Get(chrome_details_.GetProfile()); | |
| 1018 DCHECK(volume_manager); | |
| 1019 | |
| 1020 const bool writable = | |
| 1021 params->options.writable.get() && *params->options.writable.get(); | |
| 1022 if (writable && | |
| 1023 !app_file_handler_util::HasFileSystemWritePermission(extension_.get())) { | |
| 1024 return RespondNow(Error(kRequiresFileSystemWriteError)); | |
| 1025 } | 956 } |
| 1026 | 957 |
| 1027 base::WeakPtr<file_manager::Volume> volume = | 958 delegate->RequestFileSystem( |
| 1028 volume_manager->FindVolumeById(params->options.volume_id); | 959 browser_context(), this, *extension(), params->options.volume_id, |
| 1029 if (!volume.get()) | 960 params->options.writable.get() && *params->options.writable.get(), |
| 1030 return RespondNow(Error(kVolumeNotFoundError)); | 961 base::Bind(&FileSystemRequestFileSystemFunction::OnGotFileSystem, this), |
| 962 base::Bind(&FileSystemRequestFileSystemFunction::OnError, this)); |
| 1031 | 963 |
| 1032 const GURL site = | 964 return did_respond() ? AlreadyResponded() : RespondLater(); |
| 1033 util::GetSiteForExtensionId(extension_id(), chrome_details_.GetProfile()); | |
| 1034 scoped_refptr<storage::FileSystemContext> file_system_context = | |
| 1035 content::BrowserContext::GetStoragePartitionForSite( | |
| 1036 chrome_details_.GetProfile(), site) | |
| 1037 ->GetFileSystemContext(); | |
| 1038 storage::ExternalFileSystemBackend* const backend = | |
| 1039 file_system_context->external_backend(); | |
| 1040 DCHECK(backend); | |
| 1041 | |
| 1042 base::FilePath virtual_path; | |
| 1043 if (!backend->GetVirtualPath(volume->mount_path(), &virtual_path)) | |
| 1044 return RespondNow(Error(kSecurityError)); | |
| 1045 | |
| 1046 if (writable && (volume->is_read_only())) | |
| 1047 return RespondNow(Error(kSecurityError)); | |
| 1048 | |
| 1049 consent_provider.RequestConsent( | |
| 1050 *extension(), volume, writable, | |
| 1051 base::Bind(&FileSystemRequestFileSystemFunction::OnConsentReceived, this, | |
| 1052 volume, writable)); | |
| 1053 return RespondLater(); | |
| 1054 } | 965 } |
| 1055 | 966 |
| 1056 void FileSystemRequestFileSystemFunction::OnConsentReceived( | 967 void FileSystemRequestFileSystemFunction::OnGotFileSystem( |
| 1057 const base::WeakPtr<file_manager::Volume>& volume, | 968 const std::string& id, |
| 1058 bool writable, | 969 const std::string& path) { |
| 1059 ConsentProvider::Consent result) { | |
| 1060 using file_manager::VolumeManager; | |
| 1061 using file_manager::Volume; | |
| 1062 | |
| 1063 // Render frame host can be gone before this callback method is executed. | |
| 1064 if (!render_frame_host()) { | |
| 1065 Respond(Error("")); | |
| 1066 return; | |
| 1067 } | |
| 1068 | |
| 1069 switch (result) { | |
| 1070 case ConsentProvider::CONSENT_REJECTED: | |
| 1071 Respond(Error(kSecurityError)); | |
| 1072 return; | |
| 1073 | |
| 1074 case ConsentProvider::CONSENT_IMPOSSIBLE: | |
| 1075 Respond(Error(kConsentImpossible)); | |
| 1076 return; | |
| 1077 | |
| 1078 case ConsentProvider::CONSENT_GRANTED: | |
| 1079 break; | |
| 1080 } | |
| 1081 | |
| 1082 if (!volume.get()) { | |
| 1083 Respond(Error(kVolumeNotFoundError)); | |
| 1084 return; | |
| 1085 } | |
| 1086 | |
| 1087 const GURL site = | |
| 1088 util::GetSiteForExtensionId(extension_id(), chrome_details_.GetProfile()); | |
| 1089 scoped_refptr<storage::FileSystemContext> file_system_context = | |
| 1090 content::BrowserContext::GetStoragePartitionForSite( | |
| 1091 chrome_details_.GetProfile(), site) | |
| 1092 ->GetFileSystemContext(); | |
| 1093 storage::ExternalFileSystemBackend* const backend = | |
| 1094 file_system_context->external_backend(); | |
| 1095 DCHECK(backend); | |
| 1096 | |
| 1097 base::FilePath virtual_path; | |
| 1098 if (!backend->GetVirtualPath(volume->mount_path(), &virtual_path)) { | |
| 1099 Respond(Error(kSecurityError)); | |
| 1100 return; | |
| 1101 } | |
| 1102 | |
| 1103 storage::IsolatedContext* const isolated_context = | |
| 1104 storage::IsolatedContext::GetInstance(); | |
| 1105 DCHECK(isolated_context); | |
| 1106 | |
| 1107 const storage::FileSystemURL original_url = | |
| 1108 file_system_context->CreateCrackedFileSystemURL( | |
| 1109 GURL(std::string(kExtensionScheme) + url::kStandardSchemeSeparator + | |
| 1110 extension_id()), | |
| 1111 storage::kFileSystemTypeExternal, virtual_path); | |
| 1112 | |
| 1113 // Set a fixed register name, as the automatic one would leak the mount point | |
| 1114 // directory. | |
| 1115 std::string register_name = "fs"; | |
| 1116 const std::string file_system_id = | |
| 1117 isolated_context->RegisterFileSystemForPath( | |
| 1118 storage::kFileSystemTypeNativeForPlatformApp, | |
| 1119 std::string() /* file_system_id */, original_url.path(), | |
| 1120 ®ister_name); | |
| 1121 if (file_system_id.empty()) { | |
| 1122 Respond(Error(kSecurityError)); | |
| 1123 return; | |
| 1124 } | |
| 1125 | |
| 1126 backend->GrantFileAccessToExtension(extension_->id(), virtual_path); | |
| 1127 | |
| 1128 // Grant file permissions to the renderer hosting component. | |
| 1129 content::ChildProcessSecurityPolicy* policy = | |
| 1130 content::ChildProcessSecurityPolicy::GetInstance(); | |
| 1131 DCHECK(policy); | |
| 1132 | |
| 1133 // Read-only permisisons. | |
| 1134 policy->GrantReadFile(render_frame_host()->GetProcess()->GetID(), | |
| 1135 volume->mount_path()); | |
| 1136 policy->GrantReadFileSystem(render_frame_host()->GetProcess()->GetID(), | |
| 1137 file_system_id); | |
| 1138 | |
| 1139 // Additional write permissions. | |
| 1140 if (writable) { | |
| 1141 policy->GrantCreateReadWriteFile(render_frame_host()->GetProcess()->GetID(), | |
| 1142 volume->mount_path()); | |
| 1143 policy->GrantCopyInto(render_frame_host()->GetProcess()->GetID(), | |
| 1144 volume->mount_path()); | |
| 1145 policy->GrantWriteFileSystem(render_frame_host()->GetProcess()->GetID(), | |
| 1146 file_system_id); | |
| 1147 policy->GrantDeleteFromFileSystem( | |
| 1148 render_frame_host()->GetProcess()->GetID(), file_system_id); | |
| 1149 policy->GrantCreateFileForFileSystem( | |
| 1150 render_frame_host()->GetProcess()->GetID(), file_system_id); | |
| 1151 } | |
| 1152 | |
| 1153 std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue()); | 970 std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue()); |
| 1154 dict->SetString("file_system_id", file_system_id); | 971 dict->SetString("file_system_id", id); |
| 1155 dict->SetString("file_system_path", register_name); | 972 dict->SetString("file_system_path", path); |
| 1156 | |
| 1157 Respond(OneArgument(std::move(dict))); | 973 Respond(OneArgument(std::move(dict))); |
| 1158 } | 974 } |
| 1159 | 975 |
| 1160 FileSystemGetVolumeListFunction::FileSystemGetVolumeListFunction() | 976 void FileSystemRequestFileSystemFunction::OnError(const std::string& error) { |
| 1161 : chrome_details_(this) {} | 977 Respond(Error(error)); |
| 978 } |
| 979 |
| 980 FileSystemGetVolumeListFunction::FileSystemGetVolumeListFunction() {} |
| 1162 | 981 |
| 1163 FileSystemGetVolumeListFunction::~FileSystemGetVolumeListFunction() {} | 982 FileSystemGetVolumeListFunction::~FileSystemGetVolumeListFunction() {} |
| 1164 | 983 |
| 1165 ExtensionFunction::ResponseAction FileSystemGetVolumeListFunction::Run() { | 984 ExtensionFunction::ResponseAction FileSystemGetVolumeListFunction::Run() { |
| 985 FileSystemDelegate* delegate = |
| 986 ExtensionsAPIClient::Get()->GetFileSystemDelegate(); |
| 987 DCHECK(delegate); |
| 1166 // Only kiosk apps in kiosk sessions can use this API. | 988 // Only kiosk apps in kiosk sessions can use this API. |
| 1167 // Additionally it is enabled for whitelisted component extensions and apps. | 989 // Additionally it is enabled for whitelisted component extensions and apps. |
| 1168 file_system_api::ConsentProviderDelegate consent_provider_delegate( | 990 if (!delegate->IsGrantable(browser_context(), render_frame_host(), |
| 1169 chrome_details_.GetProfile(), render_frame_host()); | 991 *extension())) { |
| 1170 file_system_api::ConsentProvider consent_provider(&consent_provider_delegate); | 992 return RespondNow(Error(kNotSupportedOnNonKioskSessionError)); |
| 993 } |
| 1171 | 994 |
| 1172 if (!consent_provider.IsGrantable(*extension())) | 995 delegate->GetVolumeList( |
| 1173 return RespondNow(Error(kNotSupportedOnNonKioskSessionError)); | 996 browser_context(), |
| 1174 std::vector<api::file_system::Volume> result_volume_list; | 997 base::Bind(&FileSystemGetVolumeListFunction::OnGotVolumeList, this), |
| 1175 FillVolumeList(chrome_details_.GetProfile(), &result_volume_list); | 998 base::Bind(&FileSystemGetVolumeListFunction::OnError, this)); |
| 1176 | 999 |
| 1177 return RespondNow(ArgumentList( | 1000 return did_respond() ? AlreadyResponded() : RespondLater(); |
| 1178 api::file_system::GetVolumeList::Results::Create(result_volume_list))); | 1001 } |
| 1002 |
| 1003 void FileSystemGetVolumeListFunction::OnGotVolumeList( |
| 1004 const std::vector<file_system::Volume>& volumes) { |
| 1005 Respond(ArgumentList(file_system::GetVolumeList::Results::Create(volumes))); |
| 1006 } |
| 1007 |
| 1008 void FileSystemGetVolumeListFunction::OnError(const std::string& error) { |
| 1009 Respond(Error(error)); |
| 1179 } | 1010 } |
| 1180 #endif | 1011 #endif |
| 1181 | 1012 |
| 1182 } // namespace extensions | 1013 } // namespace extensions |
| OLD | NEW |