Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(353)

Unified Diff: chrome/browser/extensions/api/file_system/chrome_file_system_delegate.cc

Issue 2934143002: Move chrome.fileSystem implementation to //extensions (Closed)
Patch Set: benwells, test fix Created 3 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: chrome/browser/extensions/api/file_system/chrome_file_system_delegate.cc
diff --git a/chrome/browser/extensions/api/file_system/file_system_api.cc b/chrome/browser/extensions/api/file_system/chrome_file_system_delegate.cc
similarity index 13%
copy from chrome/browser/extensions/api/file_system/file_system_api.cc
copy to chrome/browser/extensions/api/file_system/chrome_file_system_delegate.cc
index 8d5c628b3b36e0d2ba4dbdfb7cea602191b59580..c50da13a2143626a0d8e953e77b287ba455703ad 100644
--- a/chrome/browser/extensions/api/file_system/file_system_api.cc
+++ b/chrome/browser/extensions/api/file_system/chrome_file_system_delegate.cc
@@ -1,64 +1,46 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "chrome/browser/extensions/api/file_system/file_system_api.h"
+#include "chrome/browser/extensions/api/file_system/chrome_file_system_delegate.h"
-#include <stddef.h>
-
-#include <memory>
-#include <set>
#include <utility>
#include <vector>
-#include "apps/saved_files_service.h"
+#include "apps/saved_files_service_delegate_impl.h"
#include "base/bind.h"
+#include "base/callback.h"
#include "base/files/file_path.h"
-#include "base/files/file_util.h"
-#include "base/macros.h"
+#include "base/logging.h"
#include "base/memory/ptr_util.h"
#include "base/path_service.h"
-#include "base/strings/string_util.h"
-#include "base/strings/stringprintf.h"
-#include "base/strings/sys_string_conversions.h"
-#include "base/strings/utf_string_conversions.h"
-#include "base/task_scheduler/post_task.h"
-#include "base/value_conversions.h"
-#include "base/values.h"
-#include "build/build_config.h"
+#include "base/strings/string16.h"
#include "chrome/browser/platform_util.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/apps/directory_access_confirmation_dialog.h"
#include "chrome/browser/ui/chrome_select_file_policy.h"
#include "chrome/common/chrome_paths.h"
-#include "chrome/common/extensions/api/file_system.h"
#include "chrome/grit/generated_resources.h"
-#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/browser_context.h"
#include "content/public/browser/child_process_security_policy.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/render_process_host.h"
#include "content/public/browser/storage_partition.h"
#include "content/public/browser/web_contents.h"
#include "extensions/browser/api/file_handlers/app_file_handler_util.h"
-#include "extensions/browser/app_window/app_window.h"
-#include "extensions/browser/app_window/app_window_registry.h"
+#include "extensions/browser/api/file_system/saved_files_service_delegate.h"
+#include "extensions/browser/extension_function.h"
#include "extensions/browser/extension_prefs.h"
#include "extensions/browser/extension_system.h"
#include "extensions/browser/extension_util.h"
-#include "extensions/browser/granted_file_entry.h"
-#include "extensions/browser/path_util.h"
-#include "extensions/common/permissions/api_permission.h"
-#include "extensions/common/permissions/permissions_data.h"
-#include "net/base/mime_util.h"
+#include "extensions/common/api/file_system.h"
+#include "extensions/common/extension.h"
#include "storage/browser/fileapi/external_mount_points.h"
-#include "storage/browser/fileapi/file_system_operation_runner.h"
#include "storage/browser/fileapi/isolated_context.h"
#include "storage/common/fileapi/file_system_types.h"
#include "storage/common/fileapi/file_system_util.h"
-#include "ui/base/l10n/l10n_util.h"
-#include "ui/base/ui_base_types.h"
#include "ui/shell_dialogs/select_file_dialog.h"
-#include "ui/shell_dialogs/selected_file_info.h"
+#include "ui/shell_dialogs/select_file_policy.h"
#if defined(OS_MACOSX)
#include <CoreFoundation/CoreFoundation.h>
@@ -66,8 +48,6 @@
#endif
#if defined(OS_CHROMEOS)
-#include "base/strings/string16.h"
-#include "chrome/browser/chromeos/file_manager/filesystem_api_util.h"
#include "chrome/browser/chromeos/file_manager/volume_manager.h"
#include "extensions/browser/event_router.h"
#include "extensions/browser/extension_registry.h"
@@ -75,207 +55,61 @@
#include "url/url_constants.h"
#endif
-using apps::SavedFileEntry;
-using apps::SavedFilesService;
-using storage::IsolatedContext;
-
-const char kInvalidCallingPage[] =
- "Invalid calling page. "
- "This function can't be called from a background page.";
-const char kUserCancelled[] = "User cancelled";
-const char kWritableFileErrorFormat[] = "Error opening %s";
-const char kRequiresFileSystemWriteError[] =
- "Operation requires fileSystem.write permission";
-const char kRequiresFileSystemDirectoryError[] =
- "Operation requires fileSystem.directory permission";
-const char kMultipleUnsupportedError[] =
- "acceptsMultiple: true is only supported for 'openFile'";
-const char kUnknownIdError[] = "Unknown id";
-
-#if !defined(OS_CHROMEOS)
-const char kNotSupportedOnCurrentPlatformError[] =
- "Operation not supported on the current platform.";
-#else
-const char kNotSupportedOnNonKioskSessionError[] =
- "Operation only supported for kiosk apps running in a kiosk session.";
-const char kVolumeNotFoundError[] = "Volume not found.";
-const char kSecurityError[] = "Security error.";
-const char kConsentImpossible[] =
- "Impossible to ask for user consent as there is no app window visible.";
-#endif
-
namespace extensions {
namespace file_system = api::file_system;
-namespace ChooseEntry = file_system::ChooseEntry;
-
-namespace {
-
-bool g_skip_picker_for_test = false;
-bool g_use_suggested_path_for_test = false;
-base::FilePath* g_path_to_be_picked_for_test;
-std::vector<base::FilePath>* g_paths_to_be_picked_for_test;
-bool g_skip_directory_confirmation_for_test = false;
-bool g_allow_directory_access_for_test = false;
-
-// Expand the mime-types and extensions provided in an AcceptOption, returning
-// them within the passed extension vector. Returns false if no valid types
-// were found.
-bool GetFileTypesFromAcceptOption(
- const file_system::AcceptOption& accept_option,
- std::vector<base::FilePath::StringType>* extensions,
- base::string16* description) {
- std::set<base::FilePath::StringType> extension_set;
- int description_id = 0;
-
- if (accept_option.mime_types.get()) {
- std::vector<std::string>* list = accept_option.mime_types.get();
- bool valid_type = false;
- for (std::vector<std::string>::const_iterator iter = list->begin();
- iter != list->end(); ++iter) {
- std::vector<base::FilePath::StringType> inner;
- std::string accept_type = base::ToLowerASCII(*iter);
- net::GetExtensionsForMimeType(accept_type, &inner);
- if (inner.empty())
- continue;
-
- if (valid_type)
- description_id = 0; // We already have an accept type with label; if
- // we find another, give up and use the default.
- else if (accept_type == "image/*")
- description_id = IDS_IMAGE_FILES;
- else if (accept_type == "audio/*")
- description_id = IDS_AUDIO_FILES;
- else if (accept_type == "video/*")
- description_id = IDS_VIDEO_FILES;
-
- extension_set.insert(inner.begin(), inner.end());
- valid_type = true;
- }
- }
-
- if (accept_option.extensions.get()) {
- std::vector<std::string>* list = accept_option.extensions.get();
- for (std::vector<std::string>::const_iterator iter = list->begin();
- iter != list->end(); ++iter) {
- std::string extension = base::ToLowerASCII(*iter);
-#if defined(OS_WIN)
- extension_set.insert(base::UTF8ToWide(*iter));
-#else
- extension_set.insert(*iter);
-#endif
- }
- }
-
- extensions->assign(extension_set.begin(), extension_set.end());
- if (extensions->empty())
- return false;
-
- if (accept_option.description.get())
- *description = base::UTF8ToUTF16(*accept_option.description);
- else if (description_id)
- *description = l10n_util::GetStringUTF16(description_id);
-
- return true;
-}
-// Key for the path of the directory of the file last chosen by the user in
-// response to a chrome.fileSystem.chooseEntry() call.
-const char kLastChooseEntryDirectory[] = "last_choose_file_directory";
-
-const int kGraylistedPaths[] = {
- base::DIR_HOME,
-#if defined(OS_WIN)
- base::DIR_PROGRAM_FILES, base::DIR_PROGRAM_FILESX86, base::DIR_WINDOWS,
-#endif
-};
-
-typedef base::Callback<void(std::unique_ptr<base::File::Info>)>
- FileInfoOptCallback;
+#if defined(OS_CHROMEOS)
+using file_system_api::ConsentProvider;
+using file_system_api::ConsentProviderDelegate;
-// Passes optional file info to the UI thread depending on |result| and |info|.
-void PassFileInfoToUIThread(const FileInfoOptCallback& callback,
- base::File::Error result,
- const base::File::Info& info) {
- DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
- std::unique_ptr<base::File::Info> file_info(
- result == base::File::FILE_OK ? new base::File::Info(info) : NULL);
- content::BrowserThread::PostTask(
- content::BrowserThread::UI, FROM_HERE,
- base::BindOnce(callback, base::Passed(&file_info)));
-}
+namespace {
-// Gets a WebContents instance handle for a platform app hosted in
-// |render_frame_host|. If not found, then returns NULL.
-content::WebContents* GetWebContentsForRenderFrameHost(
- Profile* profile,
- content::RenderFrameHost* render_frame_host) {
- content::WebContents* web_contents =
- content::WebContents::FromRenderFrameHost(render_frame_host);
- // Check if there is an app window associated with the web contents; if not,
- // return null.
- return AppWindowRegistry::Get(profile)->GetAppWindowForWebContents(
- web_contents)
- ? web_contents
- : nullptr;
-}
+const char kConsentImpossible[] =
+ "Impossible to ask for user consent as there is no app window visible.";
+const char kNotSupportedOnNonKioskSessionError[] =
+ "Operation only supported for kiosk apps running in a kiosk session.";
+const char kRequiresFileSystemWriteError[] =
+ "Operation requires fileSystem.write permission";
+const char kSecurityError[] = "Security error.";
+const char kVolumeNotFoundError[] = "Volume not found.";
-#if defined(OS_CHROMEOS)
// Fills a list of volumes mounted in the system.
-void FillVolumeList(Profile* profile,
- std::vector<api::file_system::Volume>* result) {
+void FillVolumeList(content::BrowserContext* browser_context,
+ std::vector<file_system::Volume>* result) {
file_manager::VolumeManager* const volume_manager =
- file_manager::VolumeManager::Get(profile);
+ file_manager::VolumeManager::Get(browser_context);
DCHECK(volume_manager);
const auto& volume_list = volume_manager->GetVolumeList();
// Convert volume_list to result_volume_list.
for (const auto& volume : volume_list) {
- api::file_system::Volume result_volume;
+ file_system::Volume result_volume;
result_volume.volume_id = volume->volume_id();
result_volume.writable = !volume->is_read_only();
result->push_back(std::move(result_volume));
}
}
-#endif
} // namespace
namespace file_system_api {
-base::FilePath GetLastChooseEntryDirectory(const ExtensionPrefs* prefs,
- const std::string& extension_id) {
- base::FilePath path;
- std::string string_path;
- if (prefs->ReadPrefAsString(extension_id, kLastChooseEntryDirectory,
- &string_path)) {
- path = base::FilePath::FromUTF8Unsafe(string_path);
- }
- return path;
-}
-
-void SetLastChooseEntryDirectory(ExtensionPrefs* prefs,
- const std::string& extension_id,
- const base::FilePath& path) {
- prefs->UpdateExtensionPref(extension_id, kLastChooseEntryDirectory,
- base::CreateFilePathValue(path));
-}
-
-#if defined(OS_CHROMEOS)
-void DispatchVolumeListChangeEvent(Profile* profile) {
- DCHECK(profile);
- EventRouter* const event_router = EventRouter::Get(profile);
+void DispatchVolumeListChangeEvent(content::BrowserContext* browser_context) {
+ DCHECK(browser_context);
+ EventRouter* const event_router = EventRouter::Get(browser_context);
if (!event_router) // Possible on shutdown.
return;
- ExtensionRegistry* const registry = ExtensionRegistry::Get(profile);
+ ExtensionRegistry* const registry = ExtensionRegistry::Get(browser_context);
if (!registry) // Possible on shutdown.
return;
- ConsentProviderDelegate consent_provider_delegate(profile, nullptr);
+ ConsentProviderDelegate consent_provider_delegate(
+ Profile::FromBrowserContext(browser_context));
ConsentProvider consent_provider(&consent_provider_delegate);
- api::file_system::VolumeListChangedEvent event_args;
- FillVolumeList(profile, &event_args.volumes);
+ file_system::VolumeListChangedEvent event_args;
+ FillVolumeList(browser_context, &event_args.volumes);
for (const auto& extension : registry->enabled_extensions()) {
if (!consent_provider.IsGrantable(*extension.get()))
continue;
@@ -283,839 +117,168 @@ void DispatchVolumeListChangeEvent(Profile* profile) {
extension->id(),
base::MakeUnique<Event>(
events::FILE_SYSTEM_ON_VOLUME_LIST_CHANGED,
- api::file_system::OnVolumeListChanged::kEventName,
- api::file_system::OnVolumeListChanged::Create(event_args)));
+ file_system::OnVolumeListChanged::kEventName,
+ file_system::OnVolumeListChanged::Create(event_args)));
}
}
-#endif
} // namespace file_system_api
+#endif // defined(OS_CHROMEOS)
-#if defined(OS_CHROMEOS)
-using file_system_api::ConsentProvider;
-#endif
-
-ExtensionFunction::ResponseAction FileSystemGetDisplayPathFunction::Run() {
- std::string filesystem_name;
- std::string filesystem_path;
- EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &filesystem_name));
- EXTENSION_FUNCTION_VALIDATE(args_->GetString(1, &filesystem_path));
+ChromeFileSystemDelegate::ChromeFileSystemDelegate() {}
- base::FilePath file_path;
- std::string error;
- if (!app_file_handler_util::ValidateFileEntryAndGetPath(
- filesystem_name, filesystem_path,
- render_frame_host()->GetProcess()->GetID(), &file_path, &error)) {
- return RespondNow(Error(error));
- }
+ChromeFileSystemDelegate::~ChromeFileSystemDelegate() {}
- file_path = path_util::PrettifyPath(file_path);
- return RespondNow(
- OneArgument(base::MakeUnique<base::Value>(file_path.value())));
+base::FilePath ChromeFileSystemDelegate::GetDefaultDirectory() {
+ base::FilePath documents_dir;
+ PathService::Get(chrome::DIR_USER_DOCUMENTS, &documents_dir);
+ return documents_dir;
}
-FileSystemEntryFunction::FileSystemEntryFunction()
- : multiple_(false), is_directory_(false) {}
-
-void FileSystemEntryFunction::PrepareFilesForWritableApp(
- const std::vector<base::FilePath>& paths) {
- DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
- // TODO(cmihail): Path directory set should be initialized only with the
- // paths that are actually directories, but for now we will consider
- // all paths directories in case is_directory_ is true, otherwise
- // all paths files, as this was the previous logic.
- std::set<base::FilePath> path_directory_set_ =
- is_directory_ ? std::set<base::FilePath>(paths.begin(), paths.end())
- : std::set<base::FilePath>{};
- app_file_handler_util::PrepareFilesForWritableApp(
- paths, GetProfile(), path_directory_set_,
- base::Bind(&FileSystemEntryFunction::RegisterFileSystemsAndSendResponse,
- this, paths),
- base::Bind(&FileSystemEntryFunction::HandleWritableFileError, this));
+std::unique_ptr<ui::SelectFilePolicy>
+ChromeFileSystemDelegate::CreateSelectFilePolicy(
+ content::WebContents* web_contents) {
+ return base::MakeUnique<ChromeSelectFilePolicy>(web_contents);
}
-void FileSystemEntryFunction::RegisterFileSystemsAndSendResponse(
- const std::vector<base::FilePath>& paths) {
- DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
- if (!render_frame_host())
- return;
-
- std::unique_ptr<base::DictionaryValue> result = CreateResult();
- for (const auto& path : paths)
- AddEntryToResult(path, std::string(), result.get());
- SetResult(std::move(result));
- SendResponse(true);
+scoped_refptr<ui::SelectFileDialog>
+ChromeFileSystemDelegate::CreateSelectFileDialog(
+ ui::SelectFileDialog::Listener* listener,
+ std::unique_ptr<ui::SelectFilePolicy> policy) {
+ // SelectFileDialog will take ownership of |policy|.
+ return ui::SelectFileDialog::Create(listener, policy.release());
}
-std::unique_ptr<base::DictionaryValue> FileSystemEntryFunction::CreateResult() {
- std::unique_ptr<base::DictionaryValue> result(new base::DictionaryValue());
- result->Set("entries", base::MakeUnique<base::ListValue>());
- result->SetBoolean("multiple", multiple_);
- return result;
+void ChromeFileSystemDelegate::ShowSelectFileDialogForWebContents(
+ scoped_refptr<ui::SelectFileDialog> dialog,
+ content::WebContents* web_contents,
+ ui::SelectFileDialog::Type type,
+ const base::FilePath& default_path,
+ const ui::SelectFileDialog::FileTypeInfo* file_types) {
+ gfx::NativeWindow owning_window =
+ web_contents ? platform_util::GetTopLevel(web_contents->GetNativeView())
+ : nullptr;
+ dialog->SelectFile(type, base::string16(), default_path, file_types, 0,
+ base::FilePath::StringType(), owning_window, nullptr);
}
-void FileSystemEntryFunction::AddEntryToResult(const base::FilePath& path,
- const std::string& id_override,
- base::DictionaryValue* result) {
- GrantedFileEntry file_entry = app_file_handler_util::CreateFileEntry(
- GetProfile(), extension(), render_frame_host()->GetProcess()->GetID(),
- path, is_directory_);
- base::ListValue* entries;
- bool success = result->GetList("entries", &entries);
- DCHECK(success);
-
- std::unique_ptr<base::DictionaryValue> entry(new base::DictionaryValue());
- entry->SetString("fileSystemId", file_entry.filesystem_id);
- entry->SetString("baseName", file_entry.registered_name);
- if (id_override.empty())
- entry->SetString("id", file_entry.id);
+void ChromeFileSystemDelegate::ConfirmSensitiveDirectoryAccess(
+ bool writable,
+ const base::string16& app_name,
+ content::WebContents* web_contents,
+ const base::Closure& on_accept,
+ const base::Closure& on_cancel) {
+ CreateDirectoryAccessConfirmationDialog(writable, app_name, web_contents,
+ on_accept, on_cancel);
+}
+
+bool ChromeFileSystemDelegate::GetDescriptionIdForAcceptType(
+ const std::string& accept_type,
+ int* description_id) {
+ if (accept_type == "image/*")
+ *description_id = IDS_IMAGE_FILES;
+ else if (accept_type == "audio/*")
+ *description_id = IDS_AUDIO_FILES;
+ else if (accept_type == "video/*")
+ *description_id = IDS_VIDEO_FILES;
else
- entry->SetString("id", id_override);
- entry->SetBoolean("isDirectory", is_directory_);
- entries->Append(std::move(entry));
-}
-
-void FileSystemEntryFunction::HandleWritableFileError(
- const base::FilePath& error_path) {
- DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
- error_ = base::StringPrintf(kWritableFileErrorFormat,
- error_path.BaseName().AsUTF8Unsafe().c_str());
- SendResponse(false);
-}
-
-bool FileSystemGetWritableEntryFunction::RunAsync() {
- std::string filesystem_name;
- std::string filesystem_path;
- EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &filesystem_name));
- EXTENSION_FUNCTION_VALIDATE(args_->GetString(1, &filesystem_path));
-
- if (!app_file_handler_util::HasFileSystemWritePermission(extension_.get())) {
- error_ = kRequiresFileSystemWriteError;
- return false;
- }
-
- if (!app_file_handler_util::ValidateFileEntryAndGetPath(
- filesystem_name, filesystem_path,
- render_frame_host()->GetProcess()->GetID(), &path_, &error_))
return false;
-
- base::PostTaskWithTraitsAndReply(
- FROM_HERE, {base::MayBlock(), base::TaskPriority::BACKGROUND},
- base::BindOnce(&FileSystemGetWritableEntryFunction::SetIsDirectoryAsync,
- this),
- base::BindOnce(
- &FileSystemGetWritableEntryFunction::CheckPermissionAndSendResponse,
- this));
return true;
}
-void FileSystemGetWritableEntryFunction::CheckPermissionAndSendResponse() {
- DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
- if (is_directory_ && !extension_->permissions_data()->HasAPIPermission(
- APIPermission::kFileSystemDirectory)) {
- error_ = kRequiresFileSystemDirectoryError;
- SendResponse(false);
- }
- std::vector<base::FilePath> paths;
- paths.push_back(path_);
- PrepareFilesForWritableApp(paths);
-}
-
-void FileSystemGetWritableEntryFunction::SetIsDirectoryAsync() {
- if (base::DirectoryExists(path_)) {
- is_directory_ = true;
- }
-}
-
-ExtensionFunction::ResponseAction FileSystemIsWritableEntryFunction::Run() {
- std::string filesystem_name;
- std::string filesystem_path;
- EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &filesystem_name));
- EXTENSION_FUNCTION_VALIDATE(args_->GetString(1, &filesystem_path));
-
- std::string filesystem_id;
- if (!storage::CrackIsolatedFileSystemName(filesystem_name, &filesystem_id))
- return RespondNow(Error(app_file_handler_util::kInvalidParameters));
-
- content::ChildProcessSecurityPolicy* policy =
- content::ChildProcessSecurityPolicy::GetInstance();
- int renderer_id = render_frame_host()->GetProcess()->GetID();
- bool is_writable = policy->CanReadWriteFileSystem(renderer_id, filesystem_id);
-
- return RespondNow(OneArgument(base::MakeUnique<base::Value>(is_writable)));
-}
-
-// Handles showing a dialog to the user to ask for the filename for a file to
-// save or open.
-class FileSystemChooseEntryFunction::FilePicker
- : public ui::SelectFileDialog::Listener {
- public:
- FilePicker(FileSystemChooseEntryFunction* function,
- content::WebContents* web_contents,
- const base::FilePath& suggested_name,
- const ui::SelectFileDialog::FileTypeInfo& file_type_info,
- ui::SelectFileDialog::Type picker_type)
- : function_(function) {
- select_file_dialog_ = ui::SelectFileDialog::Create(
- this, new ChromeSelectFilePolicy(web_contents));
- gfx::NativeWindow owning_window =
- web_contents ? platform_util::GetTopLevel(web_contents->GetNativeView())
- : NULL;
-
- if (g_skip_picker_for_test) {
- if (g_use_suggested_path_for_test) {
- content::BrowserThread::PostTask(
- content::BrowserThread::UI, FROM_HERE,
- base::BindOnce(
- &FileSystemChooseEntryFunction::FilePicker::FileSelected,
- base::Unretained(this), suggested_name, 1,
- static_cast<void*>(NULL)));
- } else if (g_path_to_be_picked_for_test) {
- content::BrowserThread::PostTask(
- content::BrowserThread::UI, FROM_HERE,
- base::BindOnce(
- &FileSystemChooseEntryFunction::FilePicker::FileSelected,
- base::Unretained(this), *g_path_to_be_picked_for_test, 1,
- static_cast<void*>(NULL)));
- } else if (g_paths_to_be_picked_for_test) {
- content::BrowserThread::PostTask(
- content::BrowserThread::UI, FROM_HERE,
- base::BindOnce(
- &FileSystemChooseEntryFunction::FilePicker::MultiFilesSelected,
- base::Unretained(this), *g_paths_to_be_picked_for_test,
- static_cast<void*>(NULL)));
- } else {
- content::BrowserThread::PostTask(
- content::BrowserThread::UI, FROM_HERE,
- base::BindOnce(&FileSystemChooseEntryFunction::FilePicker::
- FileSelectionCanceled,
- base::Unretained(this), static_cast<void*>(NULL)));
- }
- return;
- }
-
- select_file_dialog_->SelectFile(
- picker_type, base::string16(), suggested_name, &file_type_info, 0,
- base::FilePath::StringType(), owning_window, NULL);
- }
-
- ~FilePicker() override {}
-
- private:
- // ui::SelectFileDialog::Listener implementation.
- void FileSelected(const base::FilePath& path,
- int index,
- void* params) override {
- std::vector<base::FilePath> paths;
- paths.push_back(path);
- MultiFilesSelected(paths, params);
- }
-
- void FileSelectedWithExtraInfo(const ui::SelectedFileInfo& file,
- int index,
- void* params) override {
- // Normally, file.local_path is used because it is a native path to the
- // local read-only cached file in the case of remote file system like
- // Chrome OS's Google Drive integration. Here, however, |file.file_path| is
- // necessary because we need to create a FileEntry denoting the remote file,
- // not its cache. On other platforms than Chrome OS, they are the same.
- //
- // TODO(kinaba): remove this, once after the file picker implements proper
- // switch of the path treatment depending on the |allowed_paths|.
- FileSelected(file.file_path, index, params);
- }
-
- void MultiFilesSelected(const std::vector<base::FilePath>& files,
- void* params) override {
- function_->FilesSelected(files);
- delete this;
- }
-
- void MultiFilesSelectedWithExtraInfo(
- const std::vector<ui::SelectedFileInfo>& files,
- void* params) override {
- std::vector<base::FilePath> paths;
- for (std::vector<ui::SelectedFileInfo>::const_iterator it = files.begin();
- it != files.end(); ++it) {
- paths.push_back(it->file_path);
- }
- MultiFilesSelected(paths, params);
- }
-
- void FileSelectionCanceled(void* params) override {
- function_->FileSelectionCanceled();
- delete this;
- }
-
- scoped_refptr<ui::SelectFileDialog> select_file_dialog_;
- scoped_refptr<FileSystemChooseEntryFunction> function_;
-
- DISALLOW_COPY_AND_ASSIGN(FilePicker);
-};
-
-void FileSystemChooseEntryFunction::ShowPicker(
- const ui::SelectFileDialog::FileTypeInfo& file_type_info,
- ui::SelectFileDialog::Type picker_type) {
- // TODO(asargent/benwells) - As a short term remediation for crbug.com/179010
- // we're adding the ability for a whitelisted extension to use this API since
- // chrome.fileBrowserHandler.selectFile is ChromeOS-only. Eventually we'd
- // like a better solution and likely this code will go back to being
- // platform-app only.
- content::WebContents* const web_contents =
- extension_->is_platform_app()
- ? GetWebContentsForRenderFrameHost(GetProfile(), render_frame_host())
- : GetAssociatedWebContents();
- if (!web_contents) {
- error_ = kInvalidCallingPage;
- SendResponse(false);
- return;
- }
-
- // The file picker will hold a reference to this function instance, preventing
- // its destruction (and subsequent sending of the function response) until the
- // user has selected a file or cancelled the picker. At that point, the picker
- // will delete itself, which will also free the function instance.
- new FilePicker(this, web_contents, initial_path_, file_type_info,
- picker_type);
-}
-
-// static
-void FileSystemChooseEntryFunction::SkipPickerAndAlwaysSelectPathForTest(
- base::FilePath* path) {
- g_skip_picker_for_test = true;
- g_use_suggested_path_for_test = false;
- g_path_to_be_picked_for_test = path;
- g_paths_to_be_picked_for_test = NULL;
-}
-
-void FileSystemChooseEntryFunction::SkipPickerAndAlwaysSelectPathsForTest(
- std::vector<base::FilePath>* paths) {
- g_skip_picker_for_test = true;
- g_use_suggested_path_for_test = false;
- g_paths_to_be_picked_for_test = paths;
-}
-
-// static
-void FileSystemChooseEntryFunction::SkipPickerAndSelectSuggestedPathForTest() {
- g_skip_picker_for_test = true;
- g_use_suggested_path_for_test = true;
- g_path_to_be_picked_for_test = NULL;
- g_paths_to_be_picked_for_test = NULL;
-}
-
-// static
-void FileSystemChooseEntryFunction::SkipPickerAndAlwaysCancelForTest() {
- g_skip_picker_for_test = true;
- g_use_suggested_path_for_test = false;
- g_path_to_be_picked_for_test = NULL;
- g_paths_to_be_picked_for_test = NULL;
-}
-
-// static
-void FileSystemChooseEntryFunction::StopSkippingPickerForTest() {
- g_skip_picker_for_test = false;
-}
-
-// static
-void FileSystemChooseEntryFunction::SkipDirectoryConfirmationForTest() {
- g_skip_directory_confirmation_for_test = true;
- g_allow_directory_access_for_test = true;
-}
-
-// static
-void FileSystemChooseEntryFunction::AutoCancelDirectoryConfirmationForTest() {
- g_skip_directory_confirmation_for_test = true;
- g_allow_directory_access_for_test = false;
-}
-
-// static
-void FileSystemChooseEntryFunction::StopSkippingDirectoryConfirmationForTest() {
- g_skip_directory_confirmation_for_test = false;
-}
-
-// static
-void FileSystemChooseEntryFunction::RegisterTempExternalFileSystemForTest(
- const std::string& name,
- const base::FilePath& path) {
- // For testing on Chrome OS, where to deal with remote and local paths
- // smoothly, all accessed paths need to be registered in the list of
- // external mount points.
- storage::ExternalMountPoints::GetSystemInstance()->RegisterFileSystem(
- name, storage::kFileSystemTypeNativeLocal,
- storage::FileSystemMountOption(), path);
-}
-
-void FileSystemChooseEntryFunction::FilesSelected(
- const std::vector<base::FilePath>& paths) {
- DCHECK(!paths.empty());
- base::FilePath last_choose_directory;
- if (is_directory_) {
- last_choose_directory = paths[0];
- } else {
- last_choose_directory = paths[0].DirName();
- }
- file_system_api::SetLastChooseEntryDirectory(
- ExtensionPrefs::Get(GetProfile()), extension()->id(),
- last_choose_directory);
- if (is_directory_) {
- // Get the WebContents for the app window to be the parent window of the
- // confirmation dialog if necessary.
- content::WebContents* const web_contents =
- GetWebContentsForRenderFrameHost(GetProfile(), render_frame_host());
- if (!web_contents) {
- error_ = kInvalidCallingPage;
- SendResponse(false);
- return;
- }
-
- DCHECK_EQ(paths.size(), 1u);
- bool non_native_path = false;
-#if defined(OS_CHROMEOS)
- non_native_path =
- file_manager::util::IsUnderNonNativeLocalPath(GetProfile(), paths[0]);
-#endif
-
- base::PostTaskWithTraits(
- FROM_HERE, {base::MayBlock(), base::TaskPriority::BACKGROUND},
- base::BindOnce(
- &FileSystemChooseEntryFunction::ConfirmDirectoryAccessAsync, this,
- non_native_path, paths, web_contents));
- return;
- }
-
- OnDirectoryAccessConfirmed(paths);
-}
-
-void FileSystemChooseEntryFunction::FileSelectionCanceled() {
- error_ = kUserCancelled;
- SendResponse(false);
-}
-
-void FileSystemChooseEntryFunction::ConfirmDirectoryAccessAsync(
- bool non_native_path,
- const std::vector<base::FilePath>& paths,
- content::WebContents* web_contents) {
- const base::FilePath check_path =
- non_native_path ? paths[0] : base::MakeAbsoluteFilePath(paths[0]);
- if (check_path.empty()) {
- content::BrowserThread::PostTask(
- content::BrowserThread::UI, FROM_HERE,
- base::BindOnce(&FileSystemChooseEntryFunction::FileSelectionCanceled,
- this));
- return;
- }
-
- for (size_t i = 0; i < arraysize(kGraylistedPaths); i++) {
- base::FilePath graylisted_path;
- if (PathService::Get(kGraylistedPaths[i], &graylisted_path) &&
- (check_path == graylisted_path ||
- check_path.IsParent(graylisted_path))) {
- if (g_skip_directory_confirmation_for_test) {
- if (g_allow_directory_access_for_test) {
- break;
- } else {
- content::BrowserThread::PostTask(
- content::BrowserThread::UI, FROM_HERE,
- base::BindOnce(
- &FileSystemChooseEntryFunction::FileSelectionCanceled, this));
- }
- return;
- }
-
- content::BrowserThread::PostTask(
- content::BrowserThread::UI, FROM_HERE,
- base::BindOnce(
- CreateDirectoryAccessConfirmationDialog,
- app_file_handler_util::HasFileSystemWritePermission(
- extension_.get()),
- base::UTF8ToUTF16(extension_->name()), web_contents,
- base::Bind(
- &FileSystemChooseEntryFunction::OnDirectoryAccessConfirmed,
- this, paths),
- base::Bind(&FileSystemChooseEntryFunction::FileSelectionCanceled,
- this)));
- return;
- }
- }
-
- content::BrowserThread::PostTask(
- content::BrowserThread::UI, FROM_HERE,
- base::BindOnce(&FileSystemChooseEntryFunction::OnDirectoryAccessConfirmed,
- this, paths));
-}
-
-void FileSystemChooseEntryFunction::OnDirectoryAccessConfirmed(
- const std::vector<base::FilePath>& paths) {
- if (app_file_handler_util::HasFileSystemWritePermission(extension_.get())) {
- PrepareFilesForWritableApp(paths);
- return;
- }
-
- // Don't need to check the file, it's for reading.
- RegisterFileSystemsAndSendResponse(paths);
-}
-
-void FileSystemChooseEntryFunction::BuildFileTypeInfo(
- ui::SelectFileDialog::FileTypeInfo* file_type_info,
- const base::FilePath::StringType& suggested_extension,
- const AcceptOptions* accepts,
- const bool* acceptsAllTypes) {
- file_type_info->include_all_files = true;
- if (acceptsAllTypes)
- file_type_info->include_all_files = *acceptsAllTypes;
-
- bool need_suggestion =
- !file_type_info->include_all_files && !suggested_extension.empty();
-
- if (accepts) {
- for (const file_system::AcceptOption& option : *accepts) {
- base::string16 description;
- std::vector<base::FilePath::StringType> extensions;
-
- if (!GetFileTypesFromAcceptOption(option, &extensions, &description))
- continue; // No extensions were found.
-
- file_type_info->extensions.push_back(extensions);
- file_type_info->extension_description_overrides.push_back(description);
-
- // If we still need to find suggested_extension, hunt for it inside the
- // extensions returned from GetFileTypesFromAcceptOption.
- if (need_suggestion &&
- std::find(extensions.begin(), extensions.end(),
- suggested_extension) != extensions.end()) {
- need_suggestion = false;
- }
- }
- }
-
- // If there's nothing in our accepted extension list or we couldn't find the
- // suggested extension required, then default to accepting all types.
- if (file_type_info->extensions.empty() || need_suggestion)
- file_type_info->include_all_files = true;
-}
-
-void FileSystemChooseEntryFunction::BuildSuggestion(
- const std::string* opt_name,
- base::FilePath* suggested_name,
- base::FilePath::StringType* suggested_extension) {
- if (opt_name) {
- *suggested_name = base::FilePath::FromUTF8Unsafe(*opt_name);
-
- // Don't allow any path components; shorten to the base name. This should
- // result in a relative path, but in some cases may not. Clear the
- // suggestion for safety if this is the case.
- *suggested_name = suggested_name->BaseName();
- if (suggested_name->IsAbsolute())
- *suggested_name = base::FilePath();
-
- *suggested_extension = suggested_name->Extension();
- if (!suggested_extension->empty())
- suggested_extension->erase(suggested_extension->begin()); // drop the .
- }
-}
-
-void FileSystemChooseEntryFunction::SetInitialPathAndShowPicker(
- const base::FilePath& previous_path,
- const base::FilePath& suggested_name,
- const ui::SelectFileDialog::FileTypeInfo& file_type_info,
- ui::SelectFileDialog::Type picker_type,
- bool is_previous_path_directory) {
- DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
- if (is_previous_path_directory) {
- initial_path_ = previous_path.Append(suggested_name);
- } else {
- base::FilePath documents_dir;
- if (PathService::Get(chrome::DIR_USER_DOCUMENTS, &documents_dir)) {
- initial_path_ = documents_dir.Append(suggested_name);
- } else {
- initial_path_ = suggested_name;
- }
- }
- ShowPicker(file_type_info, picker_type);
-}
-
-bool FileSystemChooseEntryFunction::RunAsync() {
- std::unique_ptr<ChooseEntry::Params> params(
- ChooseEntry::Params::Create(*args_));
- EXTENSION_FUNCTION_VALIDATE(params.get());
-
- base::FilePath suggested_name;
- ui::SelectFileDialog::FileTypeInfo file_type_info;
- ui::SelectFileDialog::Type picker_type =
- ui::SelectFileDialog::SELECT_OPEN_FILE;
-
- file_system::ChooseEntryOptions* options = params->options.get();
- if (options) {
- multiple_ = options->accepts_multiple && *options->accepts_multiple;
- if (multiple_)
- picker_type = ui::SelectFileDialog::SELECT_OPEN_MULTI_FILE;
-
- if (options->type == file_system::CHOOSE_ENTRY_TYPE_OPENWRITABLEFILE &&
- !app_file_handler_util::HasFileSystemWritePermission(
- extension_.get())) {
- error_ = kRequiresFileSystemWriteError;
- return false;
- } else if (options->type == file_system::CHOOSE_ENTRY_TYPE_SAVEFILE) {
- if (!app_file_handler_util::HasFileSystemWritePermission(
- extension_.get())) {
- error_ = kRequiresFileSystemWriteError;
- return false;
- }
- if (multiple_) {
- error_ = kMultipleUnsupportedError;
- return false;
- }
- picker_type = ui::SelectFileDialog::SELECT_SAVEAS_FILE;
- } else if (options->type == file_system::CHOOSE_ENTRY_TYPE_OPENDIRECTORY) {
- is_directory_ = true;
- if (!extension_->permissions_data()->HasAPIPermission(
- APIPermission::kFileSystemDirectory)) {
- error_ = kRequiresFileSystemDirectoryError;
- return false;
- }
- if (multiple_) {
- error_ = kMultipleUnsupportedError;
- return false;
- }
- picker_type = ui::SelectFileDialog::SELECT_FOLDER;
- }
-
- base::FilePath::StringType suggested_extension;
- BuildSuggestion(options->suggested_name.get(), &suggested_name,
- &suggested_extension);
-
- BuildFileTypeInfo(&file_type_info, suggested_extension,
- options->accepts.get(), options->accepts_all_types.get());
- }
-
- file_type_info.allowed_paths = ui::SelectFileDialog::FileTypeInfo::ANY_PATH;
-
- base::FilePath previous_path = file_system_api::GetLastChooseEntryDirectory(
- ExtensionPrefs::Get(GetProfile()), extension()->id());
-
- if (previous_path.empty()) {
- SetInitialPathAndShowPicker(previous_path, suggested_name, file_type_info,
- picker_type, false);
- return true;
- }
-
- base::Callback<void(bool)> set_initial_path_callback = base::Bind(
- &FileSystemChooseEntryFunction::SetInitialPathAndShowPicker, this,
- previous_path, suggested_name, file_type_info, picker_type);
-
-// Check whether the |previous_path| is a non-native directory.
#if defined(OS_CHROMEOS)
- if (file_manager::util::IsUnderNonNativeLocalPath(GetProfile(),
- previous_path)) {
- file_manager::util::IsNonNativeLocalPathDirectory(
- GetProfile(), previous_path, set_initial_path_callback);
- return true;
- }
-#endif
- base::PostTaskWithTraitsAndReplyWithResult(
- FROM_HERE, {base::MayBlock(), base::TaskPriority::BACKGROUND},
- base::Bind(&base::DirectoryExists, previous_path),
- set_initial_path_callback);
-
- return true;
+bool ChromeFileSystemDelegate::IsGrantable(
+ content::BrowserContext* browser_context,
+ content::RenderFrameHost* render_frame_host,
+ const Extension& extension) {
+ // Only kiosk apps in kiosk sessions can use this API.
+ // Additionally it is enabled for whitelisted component extensions and apps.
+ ConsentProviderDelegate consent_provider_delegate(
+ Profile::FromBrowserContext(browser_context));
+ ConsentProvider consent_provider(&consent_provider_delegate);
+ return consent_provider.IsGrantable(extension);
}
-bool FileSystemRetainEntryFunction::RunAsync() {
- std::string entry_id;
- EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &entry_id));
- SavedFilesService* saved_files_service = SavedFilesService::Get(GetProfile());
- // Add the file to the retain list if it is not already on there.
- if (!saved_files_service->IsRegistered(extension_->id(), entry_id)) {
- std::string filesystem_name;
- std::string filesystem_path;
- base::FilePath path;
- EXTENSION_FUNCTION_VALIDATE(args_->GetString(1, &filesystem_name));
- EXTENSION_FUNCTION_VALIDATE(args_->GetString(2, &filesystem_path));
- if (!app_file_handler_util::ValidateFileEntryAndGetPath(
- filesystem_name, filesystem_path,
- render_frame_host()->GetProcess()->GetID(), &path, &error_)) {
- return false;
- }
-
- std::string filesystem_id;
- if (!storage::CrackIsolatedFileSystemName(filesystem_name, &filesystem_id))
- return false;
-
- const GURL site = util::GetSiteForExtensionId(extension_id(), GetProfile());
- storage::FileSystemContext* const context =
- content::BrowserContext::GetStoragePartitionForSite(GetProfile(), site)
- ->GetFileSystemContext();
- const storage::FileSystemURL url = context->CreateCrackedFileSystemURL(
- site, storage::kFileSystemTypeIsolated,
- IsolatedContext::GetInstance()
- ->CreateVirtualRootPath(filesystem_id)
- .Append(base::FilePath::FromUTF8Unsafe(filesystem_path)));
-
- content::BrowserThread::PostTask(
- content::BrowserThread::IO, FROM_HERE,
- base::BindOnce(
- base::IgnoreResult(
- &storage::FileSystemOperationRunner::GetMetadata),
- context->operation_runner()->AsWeakPtr(), url,
- storage::FileSystemOperation::GET_METADATA_FIELD_IS_DIRECTORY,
- base::Bind(
- &PassFileInfoToUIThread,
- base::Bind(&FileSystemRetainEntryFunction::RetainFileEntry,
- this, entry_id, path))));
- return true;
- }
-
- saved_files_service->EnqueueFileEntry(extension_->id(), entry_id);
- SendResponse(true);
- return true;
-}
+void ChromeFileSystemDelegate::RequestFileSystem(
+ content::BrowserContext* browser_context,
+ scoped_refptr<UIThreadExtensionFunction> requester,
+ const Extension& extension,
+ std::string volume_id,
+ bool writable,
+ const FileSystemCallback& success_callback,
+ const ErrorCallback& error_callback) {
+ ConsentProviderDelegate consent_provider_delegate(
+ Profile::FromBrowserContext(browser_context));
+ ConsentProvider consent_provider(&consent_provider_delegate);
-void FileSystemRetainEntryFunction::RetainFileEntry(
- const std::string& entry_id,
- const base::FilePath& path,
- std::unique_ptr<base::File::Info> file_info) {
- if (!file_info) {
- SendResponse(false);
+ if (!consent_provider.IsGrantable(extension)) {
+ error_callback.Run(kNotSupportedOnNonKioskSessionError);
return;
}
- SavedFilesService* saved_files_service = SavedFilesService::Get(GetProfile());
- saved_files_service->RegisterFileEntry(extension_->id(), entry_id, path,
- file_info->is_directory);
- saved_files_service->EnqueueFileEntry(extension_->id(), entry_id);
- SendResponse(true);
-}
-
-ExtensionFunction::ResponseAction FileSystemIsRestorableFunction::Run() {
- std::string entry_id;
- EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &entry_id));
- return RespondNow(OneArgument(base::MakeUnique<base::Value>(
- SavedFilesService::Get(Profile::FromBrowserContext(browser_context()))
- ->IsRegistered(extension_->id(), entry_id))));
-}
-
-bool FileSystemRestoreEntryFunction::RunAsync() {
- std::string entry_id;
- bool needs_new_entry;
- EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &entry_id));
- EXTENSION_FUNCTION_VALIDATE(args_->GetBoolean(1, &needs_new_entry));
- const SavedFileEntry* file_entry =
- SavedFilesService::Get(GetProfile())
- ->GetFileEntry(extension_->id(), entry_id);
- if (!file_entry) {
- error_ = kUnknownIdError;
- return false;
- }
-
- SavedFilesService::Get(GetProfile())
- ->EnqueueFileEntry(extension_->id(), entry_id);
-
- // Only create a new file entry if the renderer requests one.
- // |needs_new_entry| will be false if the renderer already has an Entry for
- // |entry_id|.
- if (needs_new_entry) {
- is_directory_ = file_entry->is_directory;
- std::unique_ptr<base::DictionaryValue> result = CreateResult();
- AddEntryToResult(file_entry->path, file_entry->id, result.get());
- SetResult(std::move(result));
- }
- SendResponse(true);
- return true;
-}
-
-ExtensionFunction::ResponseAction FileSystemObserveDirectoryFunction::Run() {
- NOTIMPLEMENTED();
- return RespondNow(Error(kUnknownIdError));
-}
-
-ExtensionFunction::ResponseAction FileSystemUnobserveEntryFunction::Run() {
- NOTIMPLEMENTED();
- return RespondNow(Error(kUnknownIdError));
-}
-
-ExtensionFunction::ResponseAction FileSystemGetObservedEntriesFunction::Run() {
- NOTIMPLEMENTED();
- return RespondNow(Error(kUnknownIdError));
-}
-
-#if !defined(OS_CHROMEOS)
-ExtensionFunction::ResponseAction FileSystemRequestFileSystemFunction::Run() {
- using api::file_system::RequestFileSystem::Params;
- const std::unique_ptr<Params> params(Params::Create(*args_));
- EXTENSION_FUNCTION_VALIDATE(params);
-
- NOTIMPLEMENTED();
- return RespondNow(Error(kNotSupportedOnCurrentPlatformError));
-}
-
-ExtensionFunction::ResponseAction FileSystemGetVolumeListFunction::Run() {
- NOTIMPLEMENTED();
- return RespondNow(Error(kNotSupportedOnCurrentPlatformError));
-}
-#else
-
-FileSystemRequestFileSystemFunction::FileSystemRequestFileSystemFunction()
- : chrome_details_(this) {}
-
-FileSystemRequestFileSystemFunction::~FileSystemRequestFileSystemFunction() {}
-
-ExtensionFunction::ResponseAction FileSystemRequestFileSystemFunction::Run() {
- using api::file_system::RequestFileSystem::Params;
- const std::unique_ptr<Params> params(Params::Create(*args_));
- EXTENSION_FUNCTION_VALIDATE(params);
-
- // Only kiosk apps in kiosk sessions can use this API.
- // Additionally it is enabled for whitelisted component extensions and apps.
- file_system_api::ConsentProviderDelegate consent_provider_delegate(
- chrome_details_.GetProfile(), render_frame_host());
- file_system_api::ConsentProvider consent_provider(&consent_provider_delegate);
-
- if (!consent_provider.IsGrantable(*extension()))
- return RespondNow(Error(kNotSupportedOnNonKioskSessionError));
-
using file_manager::VolumeManager;
using file_manager::Volume;
- VolumeManager* const volume_manager =
- VolumeManager::Get(chrome_details_.GetProfile());
+ VolumeManager* const volume_manager = VolumeManager::Get(browser_context);
DCHECK(volume_manager);
- const bool writable =
- params->options.writable.get() && *params->options.writable.get();
if (writable &&
- !app_file_handler_util::HasFileSystemWritePermission(extension_.get())) {
- return RespondNow(Error(kRequiresFileSystemWriteError));
+ !app_file_handler_util::HasFileSystemWritePermission(&extension)) {
+ error_callback.Run(kRequiresFileSystemWriteError);
+ return;
}
base::WeakPtr<file_manager::Volume> volume =
- volume_manager->FindVolumeById(params->options.volume_id);
- if (!volume.get())
- return RespondNow(Error(kVolumeNotFoundError));
+ volume_manager->FindVolumeById(volume_id);
+ if (!volume.get()) {
+ error_callback.Run(kVolumeNotFoundError);
+ return;
+ }
const GURL site =
- util::GetSiteForExtensionId(extension_id(), chrome_details_.GetProfile());
+ util::GetSiteForExtensionId(extension.id(), browser_context);
scoped_refptr<storage::FileSystemContext> file_system_context =
- content::BrowserContext::GetStoragePartitionForSite(
- chrome_details_.GetProfile(), site)
+ content::BrowserContext::GetStoragePartitionForSite(browser_context, site)
->GetFileSystemContext();
storage::ExternalFileSystemBackend* const backend =
file_system_context->external_backend();
DCHECK(backend);
base::FilePath virtual_path;
- if (!backend->GetVirtualPath(volume->mount_path(), &virtual_path))
- return RespondNow(Error(kSecurityError));
+ if (!backend->GetVirtualPath(volume->mount_path(), &virtual_path)) {
+ error_callback.Run(kSecurityError);
+ return;
+ }
+
+ if (writable && (volume->is_read_only())) {
+ error_callback.Run(kSecurityError);
+ return;
+ }
- if (writable && (volume->is_read_only()))
- return RespondNow(Error(kSecurityError));
+ const ConsentProvider::ConsentCallback& callback = base::Bind(
+ &ChromeFileSystemDelegate::OnConsentReceived, base::Unretained(this),
Devlin 2017/06/14 14:53:22 document why this unretained is safe
michaelpg 2017/06/21 00:40:07 Maybe it's not? Calling RequestConsent below may t
Devlin 2017/06/21 14:53:30 I don't know the lifetime of the dialog, but I wou
+ browser_context, requester, success_callback, error_callback,
+ extension.id(), volume, writable);
- consent_provider.RequestConsent(
- *extension(), volume, writable,
- base::Bind(&FileSystemRequestFileSystemFunction::OnConsentReceived, this,
- volume, writable));
- return RespondLater();
+ consent_provider.RequestConsent(extension, requester->render_frame_host(),
+ volume, writable, callback);
}
-void FileSystemRequestFileSystemFunction::OnConsentReceived(
+void ChromeFileSystemDelegate::GetVolumeList(
+ content::BrowserContext* browser_context,
+ const VolumeListCallback& success_callback,
+ const ErrorCallback& error_callback) {
+ std::vector<file_system::Volume> result_volume_list;
+ FillVolumeList(browser_context, &result_volume_list);
+
+ success_callback.Run(result_volume_list);
+}
+
+void ChromeFileSystemDelegate::OnConsentReceived(
+ content::BrowserContext* browser_context,
+ scoped_refptr<UIThreadExtensionFunction> requester,
+ const FileSystemCallback& success_callback,
+ const ErrorCallback& error_callback,
+ const std::string& extension_id,
const base::WeakPtr<file_manager::Volume>& volume,
bool writable,
ConsentProvider::Consent result) {
@@ -1123,18 +286,18 @@ void FileSystemRequestFileSystemFunction::OnConsentReceived(
using file_manager::Volume;
// Render frame host can be gone before this callback method is executed.
- if (!render_frame_host()) {
- Respond(Error(""));
+ if (!requester->render_frame_host()) {
+ error_callback.Run("");
Devlin 2017/06/14 14:53:22 I know this was just copied, but prefer std::strin
michaelpg 2017/06/21 00:40:07 Done.
return;
}
switch (result) {
case ConsentProvider::CONSENT_REJECTED:
- Respond(Error(kSecurityError));
+ error_callback.Run(kSecurityError);
return;
case ConsentProvider::CONSENT_IMPOSSIBLE:
- Respond(Error(kConsentImpossible));
+ error_callback.Run(kConsentImpossible);
return;
case ConsentProvider::CONSENT_GRANTED:
@@ -1142,15 +305,13 @@ void FileSystemRequestFileSystemFunction::OnConsentReceived(
}
if (!volume.get()) {
- Respond(Error(kVolumeNotFoundError));
+ error_callback.Run(kVolumeNotFoundError);
return;
}
- const GURL site =
- util::GetSiteForExtensionId(extension_id(), chrome_details_.GetProfile());
+ const GURL site = util::GetSiteForExtensionId(extension_id, browser_context);
scoped_refptr<storage::FileSystemContext> file_system_context =
- content::BrowserContext::GetStoragePartitionForSite(
- chrome_details_.GetProfile(), site)
+ content::BrowserContext::GetStoragePartitionForSite(browser_context, site)
->GetFileSystemContext();
storage::ExternalFileSystemBackend* const backend =
file_system_context->external_backend();
@@ -1158,7 +319,7 @@ void FileSystemRequestFileSystemFunction::OnConsentReceived(
base::FilePath virtual_path;
if (!backend->GetVirtualPath(volume->mount_path(), &virtual_path)) {
- Respond(Error(kSecurityError));
+ error_callback.Run(kSecurityError);
return;
}
@@ -1169,7 +330,7 @@ void FileSystemRequestFileSystemFunction::OnConsentReceived(
const storage::FileSystemURL original_url =
file_system_context->CreateCrackedFileSystemURL(
GURL(std::string(kExtensionScheme) + url::kStandardSchemeSeparator +
- extension_id()),
+ extension_id),
storage::kFileSystemTypeExternal, virtual_path);
// Set a fixed register name, as the automatic one would leak the mount point
@@ -1181,64 +342,39 @@ void FileSystemRequestFileSystemFunction::OnConsentReceived(
std::string() /* file_system_id */, original_url.path(),
&register_name);
if (file_system_id.empty()) {
- Respond(Error(kSecurityError));
+ error_callback.Run(kSecurityError);
return;
}
- backend->GrantFileAccessToExtension(extension_->id(), virtual_path);
+ backend->GrantFileAccessToExtension(extension_id, virtual_path);
// Grant file permissions to the renderer hosting component.
content::ChildProcessSecurityPolicy* policy =
content::ChildProcessSecurityPolicy::GetInstance();
DCHECK(policy);
+ const auto process_id = requester->render_frame_host()->GetProcess()->GetID();
// Read-only permisisons.
- policy->GrantReadFile(render_frame_host()->GetProcess()->GetID(),
- volume->mount_path());
- policy->GrantReadFileSystem(render_frame_host()->GetProcess()->GetID(),
- file_system_id);
+ policy->GrantReadFile(process_id, volume->mount_path());
+ policy->GrantReadFileSystem(process_id, file_system_id);
// Additional write permissions.
if (writable) {
- policy->GrantCreateReadWriteFile(render_frame_host()->GetProcess()->GetID(),
- volume->mount_path());
- policy->GrantCopyInto(render_frame_host()->GetProcess()->GetID(),
- volume->mount_path());
- policy->GrantWriteFileSystem(render_frame_host()->GetProcess()->GetID(),
- file_system_id);
- policy->GrantDeleteFromFileSystem(
- render_frame_host()->GetProcess()->GetID(), file_system_id);
- policy->GrantCreateFileForFileSystem(
- render_frame_host()->GetProcess()->GetID(), file_system_id);
+ policy->GrantCreateReadWriteFile(process_id, volume->mount_path());
+ policy->GrantCopyInto(process_id, volume->mount_path());
+ policy->GrantWriteFileSystem(process_id, file_system_id);
+ policy->GrantDeleteFromFileSystem(process_id, file_system_id);
+ policy->GrantCreateFileForFileSystem(process_id, file_system_id);
}
- std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue());
- dict->SetString("file_system_id", file_system_id);
- dict->SetString("file_system_path", register_name);
-
- Respond(OneArgument(std::move(dict)));
+ success_callback.Run(file_system_id, register_name);
}
+#endif // defined(OS_CHROMEOS)
-FileSystemGetVolumeListFunction::FileSystemGetVolumeListFunction()
- : chrome_details_(this) {}
-
-FileSystemGetVolumeListFunction::~FileSystemGetVolumeListFunction() {}
-
-ExtensionFunction::ResponseAction FileSystemGetVolumeListFunction::Run() {
- // Only kiosk apps in kiosk sessions can use this API.
- // Additionally it is enabled for whitelisted component extensions and apps.
- file_system_api::ConsentProviderDelegate consent_provider_delegate(
- chrome_details_.GetProfile(), render_frame_host());
- file_system_api::ConsentProvider consent_provider(&consent_provider_delegate);
-
- if (!consent_provider.IsGrantable(*extension()))
- return RespondNow(Error(kNotSupportedOnNonKioskSessionError));
- std::vector<api::file_system::Volume> result_volume_list;
- FillVolumeList(chrome_details_.GetProfile(), &result_volume_list);
-
- return RespondNow(ArgumentList(
- api::file_system::GetVolumeList::Results::Create(result_volume_list)));
+std::unique_ptr<file_system_api::SavedFilesServiceDelegate>
+ChromeFileSystemDelegate::CreateSavedFilesServiceDelegate(
+ content::BrowserContext* browser_context) {
+ return base::MakeUnique<apps::SavedFilesServiceDelegateImpl>(browser_context);
}
-#endif
} // namespace extensions

Powered by Google App Engine
This is Rietveld 408576698