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 |