summaryrefslogtreecommitdiffstats
path: root/chrome/browser/extensions
diff options
context:
space:
mode:
authorbenwells@chromium.org <benwells@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-06-15 01:58:13 +0000
committerbenwells@chromium.org <benwells@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-06-15 01:58:13 +0000
commit6742976c47434825a5d8a781b2254e711357f47b (patch)
tree61d6d7f2487bd166eb18c88725071e781d93fab6 /chrome/browser/extensions
parent38e33fd5ba9b8a7dfb8b89d9d8afda04e6295cd9 (diff)
downloadchromium_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.cc142
-rw-r--r--chrome/browser/extensions/api/file_system/file_system_api.h39
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