diff options
author | benwells@chromium.org <benwells@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-06-15 01:58:13 +0000 |
---|---|---|
committer | benwells@chromium.org <benwells@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-06-15 01:58:13 +0000 |
commit | 6742976c47434825a5d8a781b2254e711357f47b (patch) | |
tree | 61d6d7f2487bd166eb18c88725071e781d93fab6 /chrome/browser/extensions | |
parent | 38e33fd5ba9b8a7dfb8b89d9d8afda04e6295cd9 (diff) | |
download | chromium_src-6742976c47434825a5d8a781b2254e711357f47b.zip chromium_src-6742976c47434825a5d8a781b2254e711357f47b.tar.gz chromium_src-6742976c47434825a5d8a781b2254e711357f47b.tar.bz2 |
Implement fileSystem.chooseFile.
This allows platform apps to prompt the user for a file to read or a file to
write. If opening (reading) the file entry returned will be read only. If
saving the file entry will be read write.
BUG=130196
TEST=Manual testing
Review URL: https://chromiumcodereview.appspot.com/10534156
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@142314 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser/extensions')
-rw-r--r-- | chrome/browser/extensions/api/file_system/file_system_api.cc | 142 | ||||
-rw-r--r-- | chrome/browser/extensions/api/file_system/file_system_api.h | 39 |
2 files changed, 150 insertions, 31 deletions
diff --git a/chrome/browser/extensions/api/file_system/file_system_api.cc b/chrome/browser/extensions/api/file_system/file_system_api.cc index bbf689e..a091e04 100644 --- a/chrome/browser/extensions/api/file_system/file_system_api.cc +++ b/chrome/browser/extensions/api/file_system/file_system_api.cc @@ -4,11 +4,14 @@ #include "chrome/browser/extensions/api/file_system/file_system_api.h" +#include "base/bind.h" #include "base/file_path.h" +#include "base/file_util.h" #include "chrome/browser/extensions/shell_window_registry.h" #include "chrome/browser/platform_util.h" #include "chrome/browser/ui/extensions/shell_window.h" #include "chrome/browser/ui/select_file_dialog.h" +#include "chrome/common/extensions/api/file_system.h" #include "content/public/browser/child_process_security_policy.h" #include "content/public/browser/render_view_host.h" #include "content/public/browser/render_process_host.h" @@ -20,6 +23,12 @@ const char kInvalidParameters[] = "Invalid parameters"; const char kSecurityError[] = "Security error"; const char kInvalidCallingPage[] = "Invalid calling page"; const char kUserCancelled[] = "User cancelled"; +const char kWritableFileError[] = "Invalid file for writing"; + +const char kSaveFileOption[] = "saveFile"; + +namespace file_system = extensions::api::file_system; +namespace ChooseFile = file_system::ChooseFile; namespace { @@ -59,6 +68,20 @@ bool GetFilePathOfFileEntry(const std::string& filesystem_name, return true; } +bool DoCheckWritableFile(const FilePath& path) { + // Don't allow links. + if (file_util::PathExists(path) && file_util::IsLink(path)) + return false; + + // Create the file if it doesn't already exist. + base::PlatformFileError error = base::PLATFORM_FILE_OK; + int creation_flags = base::PLATFORM_FILE_CREATE | + base::PLATFORM_FILE_READ | + base::PLATFORM_FILE_WRITE; + base::CreatePlatformFile(path, creation_flags, NULL, &error); + return error == base::PLATFORM_FILE_OK; +} + } // namespace namespace extensions { @@ -81,13 +104,14 @@ bool FileSystemGetDisplayPathFunction::RunImpl() { // Handles showing a dialog to the user to ask for the filename for a file to // save. -class FileSystemGetWritableFileEntryFunction::FilePicker - : public SelectFileDialog::Listener { +class FileSystemPickerFunction::FilePicker : public SelectFileDialog::Listener { public: - FilePicker(FileSystemGetWritableFileEntryFunction* function, + FilePicker(FileSystemPickerFunction* function, content::WebContents* web_contents, - const FilePath& suggested_path) + const FilePath& suggested_path, + bool for_save) : suggested_path_(suggested_path), + for_save_(for_save), function_(function) { select_file_dialog_ = SelectFileDialog::Create(this); SelectFileDialog::FileTypeInfo file_type_info; @@ -101,7 +125,9 @@ class FileSystemGetWritableFileEntryFunction::FilePicker gfx::NativeWindow owning_window = web_contents ? platform_util::GetTopLevel(web_contents->GetNativeView()) : NULL; - select_file_dialog_->SelectFile(SelectFileDialog::SELECT_SAVEAS_FILE, + select_file_dialog_->SelectFile(for_save ? + SelectFileDialog::SELECT_SAVEAS_FILE : + SelectFileDialog::SELECT_OPEN_FILE, string16(), suggested_path, &file_type_info, 0, FILE_PATH_LITERAL(""), @@ -115,7 +141,7 @@ class FileSystemGetWritableFileEntryFunction::FilePicker virtual void FileSelected(const FilePath& path, int index, void* params) OVERRIDE { - function_->FileSelected(path); + function_->FileSelected(path, for_save_); delete this; } @@ -126,25 +152,19 @@ class FileSystemGetWritableFileEntryFunction::FilePicker FilePath suggested_path_; - // For managing select file dialogs. + // for_save_ is false when using the picker to open a file, and true + // when saving. It affects the style of the dialog and also what happens + // after a file is selected by the user. + bool for_save_; + scoped_refptr<SelectFileDialog> select_file_dialog_; - scoped_refptr<FileSystemGetWritableFileEntryFunction> function_; + scoped_refptr<FileSystemPickerFunction> function_; DISALLOW_COPY_AND_ASSIGN(FilePicker); }; -bool FileSystemGetWritableFileEntryFunction::RunImpl() { - std::string filesystem_name; - std::string filesystem_path; - EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &filesystem_name)); - EXTENSION_FUNCTION_VALIDATE(args_->GetString(1, &filesystem_path)); - - FilePath suggested_path; - if (!GetFilePathOfFileEntry(filesystem_name, filesystem_path, - render_view_host_, &suggested_path, &error_)) { - return false; - } - +bool FileSystemPickerFunction::ShowPicker(const FilePath& suggested_path, + bool for_save) { ShellWindowRegistry* registry = ShellWindowRegistry::Get(profile()); DCHECK(registry); ShellWindow* shell_window = registry->GetShellWindowForRenderViewHost( @@ -158,12 +178,43 @@ bool FileSystemGetWritableFileEntryFunction::RunImpl() { // 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, shell_window->web_contents(), suggested_path); + new FilePicker(this, shell_window->web_contents(), suggested_path, for_save); return true; } -void FileSystemGetWritableFileEntryFunction::FileSelected( - const FilePath& path) { +void FileSystemPickerFunction::FileSelected(const FilePath& path, + bool for_save) { + if (for_save) { + content::BrowserThread::PostTask(content::BrowserThread::FILE, FROM_HERE, + base::Bind(&FileSystemPickerFunction::CheckWritableFile, this, path)); + return; + } + + // Don't need to check the file, it's for reading. + RegisterFileSystemAndSendResponse(path, false); +} + +void FileSystemPickerFunction::FileSelectionCanceled() { + error_ = kUserCancelled; + SendResponse(false); +} + +void FileSystemPickerFunction::CheckWritableFile(const FilePath& path) { + DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE)); + if (DoCheckWritableFile(path)) { + content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE, + base::Bind(&FileSystemPickerFunction::RegisterFileSystemAndSendResponse, + this, path, true)); + return; + } + + content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE, + base::Bind(&FileSystemPickerFunction::HandleWritableFileError, this)); +} + +void FileSystemPickerFunction::RegisterFileSystemAndSendResponse( + const FilePath& path, bool for_save) { + DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); std::set<FilePath> filesets; filesets.insert(path); @@ -176,7 +227,16 @@ void FileSystemGetWritableFileEntryFunction::FileSelected( content::ChildProcessSecurityPolicy* policy = content::ChildProcessSecurityPolicy::GetInstance(); int renderer_id = render_view_host_->GetProcess()->GetID(); - policy->GrantReadWriteFileSystem(renderer_id, filesystem_id); + if (for_save) + policy->GrantReadWriteFileSystem(renderer_id, filesystem_id); + else + policy->GrantReadFileSystem(renderer_id, filesystem_id); + + // We only need file level access for reading FileEntries. Saving FileEntries + // just needs the file system to have read/write access, which is granted + // above if required. + if (!policy->CanReadFile(renderer_id, path)) + policy->GrantReadFile(renderer_id, path); DictionaryValue* dict = new DictionaryValue(); result_.reset(dict); @@ -185,9 +245,39 @@ void FileSystemGetWritableFileEntryFunction::FileSelected( SendResponse(true); } -void FileSystemGetWritableFileEntryFunction::FileSelectionCanceled() { - error_ = kUserCancelled; +void FileSystemPickerFunction::HandleWritableFileError() { + DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); + error_ = kWritableFileError; SendResponse(false); } +bool FileSystemGetWritableFileEntryFunction::RunImpl() { + std::string filesystem_name; + std::string filesystem_path; + EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &filesystem_name)); + EXTENSION_FUNCTION_VALIDATE(args_->GetString(1, &filesystem_path)); + + FilePath suggested_path; + if (!GetFilePathOfFileEntry(filesystem_name, filesystem_path, + render_view_host_, &suggested_path, &error_)) { + return false; + } + + return ShowPicker(suggested_path, true); +} + +bool FileSystemChooseFileFunction::RunImpl() { + scoped_ptr<ChooseFile::Params> params(ChooseFile::Params::Create(*args_)); + EXTENSION_FUNCTION_VALIDATE(params.get()); + + bool for_save = false; + file_system::ChooseFileOptions* options = params->options.get(); + if (options) { + if (options->type.get() && *options->type == kSaveFileOption) + for_save = true; + } + + return ShowPicker(FilePath(), for_save); +} + } // namespace extensions diff --git a/chrome/browser/extensions/api/file_system/file_system_api.h b/chrome/browser/extensions/api/file_system/file_system_api.h index 0757736..2acf23a 100644 --- a/chrome/browser/extensions/api/file_system/file_system_api.h +++ b/chrome/browser/extensions/api/file_system/file_system_api.h @@ -19,19 +19,48 @@ class FileSystemGetDisplayPathFunction : public SyncExtensionFunction { virtual bool RunImpl() OVERRIDE; }; -class FileSystemGetWritableFileEntryFunction : public AsyncExtensionFunction { +class FileSystemPickerFunction : public AsyncExtensionFunction { + protected: + class FilePicker; + + virtual ~FileSystemPickerFunction() {} + bool ShowPicker(const FilePath& suggested_path, bool for_save); + + private: + // FileSelected and FileSelectionCanceled are called by the file picker. + void FileSelected(const FilePath& path, bool for_save); + void FileSelectionCanceled(); + + // called on the FILE thread. This is only called when a file is being chosen + // to save. The function will ensure the file exists, creating it if + // necessary, and also check that the file is not a link. + void CheckWritableFile(const FilePath& path); + + // This will finish the choose file process. This is either called directly + // from FileSelected, or from CreateFileIfNecessary. It is called on the UI + // thread. + void RegisterFileSystemAndSendResponse(const FilePath& path, bool for_save); + + // called on the UI thread if there is a problem checking a writable file. + void HandleWritableFileError(); +}; + +class FileSystemGetWritableFileEntryFunction : public FileSystemPickerFunction { public: DECLARE_EXTENSION_FUNCTION_NAME("fileSystem.getWritableFileEntry"); protected: virtual ~FileSystemGetWritableFileEntryFunction() {} virtual bool RunImpl() OVERRIDE; +}; - private: - class FilePicker; +class FileSystemChooseFileFunction : public FileSystemPickerFunction { + public: + DECLARE_EXTENSION_FUNCTION_NAME("fileSystem.chooseFile"); - void FileSelected(const FilePath& path); - void FileSelectionCanceled(); + protected: + virtual ~FileSystemChooseFileFunction() {} + virtual bool RunImpl() OVERRIDE; }; } // namespace extensions |