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