Chromium Code Reviews| Index: chrome/browser/extensions/api/file_system/file_system_api.cc |
| 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 bbf689e4c2f243d10136c6ae1e1ae1563a124e38..a091e04390e9f33d738c78cc64f6500527d34e78 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) |
|
Mihai Parparita -not on Chrome
2012/06/15 04:19:15
Nit: extra space before the *
|
| + for_save = true; |
| + } |
| + |
| + return ShowPicker(FilePath(), for_save); |
| +} |
| + |
| } // namespace extensions |