Chromium Code Reviews

Side by Side Diff: chrome/browser/extensions/api/file_system/file_system_api.cc

Issue 23146016: Add support for directory access to the file system API. (Closed) Base URL: http://git.chromium.org/chromium/src.git@simpler-write-permissions
Patch Set: rebase Created 7 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
View unified diff |
OLDNEW
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 "chrome/browser/extensions/api/file_system/file_system_api.h"
6 6
7 #include "apps/saved_files_service.h" 7 #include "apps/saved_files_service.h"
8 #include "apps/shell_window.h" 8 #include "apps/shell_window.h"
9 #include "apps/shell_window_registry.h" 9 #include "apps/shell_window_registry.h"
10 #include "base/bind.h" 10 #include "base/bind.h"
(...skipping 42 matching lines...)
53 using fileapi::IsolatedContext; 53 using fileapi::IsolatedContext;
54 54
55 const char kInvalidParameters[] = "Invalid parameters"; 55 const char kInvalidParameters[] = "Invalid parameters";
56 const char kSecurityError[] = "Security error"; 56 const char kSecurityError[] = "Security error";
57 const char kInvalidCallingPage[] = "Invalid calling page. This function can't " 57 const char kInvalidCallingPage[] = "Invalid calling page. This function can't "
58 "be called from a background page."; 58 "be called from a background page.";
59 const char kUserCancelled[] = "User cancelled"; 59 const char kUserCancelled[] = "User cancelled";
60 const char kWritableFileErrorFormat[] = "Error opening %s"; 60 const char kWritableFileErrorFormat[] = "Error opening %s";
61 const char kRequiresFileSystemWriteError[] = 61 const char kRequiresFileSystemWriteError[] =
62 "Operation requires fileSystem.write permission"; 62 "Operation requires fileSystem.write permission";
63 const char kRequiresFileSystemDirectoryError[] =
64 "Operation requires fileSystem.directory permission";
63 const char kMultipleUnsupportedError[] = 65 const char kMultipleUnsupportedError[] =
64 "acceptsMultiple: true is not supported for 'saveFile'"; 66 "acceptsMultiple: true is not supported for 'saveFile'";
65 const char kUnknownIdError[] = "Unknown id"; 67 const char kUnknownIdError[] = "Unknown id";
66 68
67 namespace file_system = extensions::api::file_system; 69 namespace file_system = extensions::api::file_system;
68 namespace ChooseEntry = file_system::ChooseEntry; 70 namespace ChooseEntry = file_system::ChooseEntry;
69 71
70 namespace { 72 namespace {
71 73
72 #if defined(OS_MACOSX) 74 #if defined(OS_MACOSX)
(...skipping 224 matching lines...)
297 render_view_host_, &file_path, &error_)) 299 render_view_host_, &file_path, &error_))
298 return false; 300 return false;
299 301
300 file_path = PrettifyPath(file_path); 302 file_path = PrettifyPath(file_path);
301 SetResult(new base::StringValue(file_path.value())); 303 SetResult(new base::StringValue(file_path.value()));
302 return true; 304 return true;
303 } 305 }
304 306
305 FileSystemEntryFunction::FileSystemEntryFunction() 307 FileSystemEntryFunction::FileSystemEntryFunction()
306 : multiple_(false), 308 : multiple_(false),
309 is_directory_(false),
307 response_(NULL) {} 310 response_(NULL) {}
308 311
309 void FileSystemEntryFunction::CheckWritableFiles( 312 void FileSystemEntryFunction::CheckWritableFiles(
310 const std::vector<base::FilePath>& paths) { 313 const std::vector<base::FilePath>& paths) {
311 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); 314 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
312 app_file_handler_util::CheckWritableFiles( 315 app_file_handler_util::CheckWritableFiles(
313 paths, 316 paths,
314 profile_, 317 profile_,
315 base::Bind(&FileSystemEntryFunction::RegisterFileSystemsAndSendResponse, 318 base::Bind(&FileSystemEntryFunction::RegisterFileSystemsAndSendResponse,
316 this, 319 this,
(...skipping 24 matching lines...)
341 344
342 void FileSystemEntryFunction::AddEntryToResponse( 345 void FileSystemEntryFunction::AddEntryToResponse(
343 const base::FilePath& path, 346 const base::FilePath& path,
344 const std::string& id_override) { 347 const std::string& id_override) {
345 DCHECK(response_); 348 DCHECK(response_);
346 extensions::app_file_handler_util::GrantedFileEntry file_entry = 349 extensions::app_file_handler_util::GrantedFileEntry file_entry =
347 extensions::app_file_handler_util::CreateFileEntry( 350 extensions::app_file_handler_util::CreateFileEntry(
348 profile(), 351 profile(),
349 GetExtension(), 352 GetExtension(),
350 render_view_host_->GetProcess()->GetID(), 353 render_view_host_->GetProcess()->GetID(),
351 path); 354 path,
355 is_directory_);
352 base::ListValue* entries; 356 base::ListValue* entries;
353 bool success = response_->GetList("entries", &entries); 357 bool success = response_->GetList("entries", &entries);
354 DCHECK(success); 358 DCHECK(success);
355 359
356 base::DictionaryValue* entry = new base::DictionaryValue(); 360 base::DictionaryValue* entry = new base::DictionaryValue();
357 entry->SetString("fileSystemId", file_entry.filesystem_id); 361 entry->SetString("fileSystemId", file_entry.filesystem_id);
358 entry->SetString("baseName", file_entry.registered_name); 362 entry->SetString("baseName", file_entry.registered_name);
359 if (id_override.empty()) 363 if (id_override.empty())
360 entry->SetString("id", file_entry.id); 364 entry->SetString("id", file_entry.id);
361 else 365 else
362 entry->SetString("id", id_override); 366 entry->SetString("id", id_override);
367 entry->SetBoolean("isDirectory", is_directory_);
363 entries->Append(entry); 368 entries->Append(entry);
364 } 369 }
365 370
366 void FileSystemEntryFunction::HandleWritableFileError( 371 void FileSystemEntryFunction::HandleWritableFileError(
367 const base::FilePath& error_path) { 372 const base::FilePath& error_path) {
368 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); 373 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
369 error_ = base::StringPrintf(kWritableFileErrorFormat, 374 error_ = base::StringPrintf(kWritableFileErrorFormat,
370 error_path.BaseName().AsUTF8Unsafe().c_str()); 375 error_path.BaseName().AsUTF8Unsafe().c_str());
371 SendResponse(false); 376 SendResponse(false);
372 } 377 }
373 378
374 bool FileSystemGetWritableEntryFunction::RunImpl() { 379 bool FileSystemGetWritableEntryFunction::RunImpl() {
375 std::string filesystem_name; 380 std::string filesystem_name;
376 std::string filesystem_path; 381 std::string filesystem_path;
377 EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &filesystem_name)); 382 EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &filesystem_name));
378 EXTENSION_FUNCTION_VALIDATE(args_->GetString(1, &filesystem_path)); 383 EXTENSION_FUNCTION_VALIDATE(args_->GetString(1, &filesystem_path));
379 384
380 if (!app_file_handler_util::HasFileSystemWritePermission(extension_)) { 385 if (!app_file_handler_util::HasFileSystemWritePermission(extension_)) {
381 error_ = kRequiresFileSystemWriteError; 386 error_ = kRequiresFileSystemWriteError;
382 return false; 387 return false;
383 } 388 }
384 389
385 base::FilePath path;
386 if (!ValidateFileEntryAndGetPath(filesystem_name, filesystem_path, 390 if (!ValidateFileEntryAndGetPath(filesystem_name, filesystem_path,
387 render_view_host_, &path, &error_)) 391 render_view_host_, &path_, &error_))
388 return false; 392 return false;
389 393
390 std::vector<base::FilePath> paths; 394 content::BrowserThread::PostTaskAndReply(
391 paths.push_back(path); 395 content::BrowserThread::FILE,
392 CheckWritableFiles(paths); 396 FROM_HERE,
397 base::Bind(
398 &FileSystemGetWritableEntryFunction::SetIsDirectoryOnFileThread,
399 this),
400 base::Bind(
401 &FileSystemGetWritableEntryFunction::CheckPermissionAndSendResponse,
402 this));
393 return true; 403 return true;
394 } 404 }
395 405
406 void FileSystemGetWritableEntryFunction::CheckPermissionAndSendResponse() {
407 if (is_directory_ &&
408 !extension_->HasAPIPermission(APIPermission::kFileSystemDirectory)) {
409 error_ = kRequiresFileSystemDirectoryError;
410 SendResponse(false);
411 }
412 std::vector<base::FilePath> paths;
413 paths.push_back(path_);
414 CheckWritableFiles(paths);
415 }
416
417 void FileSystemGetWritableEntryFunction::SetIsDirectoryOnFileThread() {
418 if (base::DirectoryExists(path_)) {
419 is_directory_ = true;
420 }
421 }
422
396 bool FileSystemIsWritableEntryFunction::RunImpl() { 423 bool FileSystemIsWritableEntryFunction::RunImpl() {
397 std::string filesystem_name; 424 std::string filesystem_name;
398 std::string filesystem_path; 425 std::string filesystem_path;
399 EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &filesystem_name)); 426 EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &filesystem_name));
400 EXTENSION_FUNCTION_VALIDATE(args_->GetString(1, &filesystem_path)); 427 EXTENSION_FUNCTION_VALIDATE(args_->GetString(1, &filesystem_path));
401 428
402 std::string filesystem_id; 429 std::string filesystem_id;
403 if (!fileapi::CrackIsolatedFileSystemName(filesystem_name, &filesystem_id)) { 430 if (!fileapi::CrackIsolatedFileSystemName(filesystem_name, &filesystem_id)) {
404 error_ = kInvalidParameters; 431 error_ = kInvalidParameters;
405 return false; 432 return false;
(...skipping 214 matching lines...)
620 initial_path_ = documents_dir.Append(suggested_name); 647 initial_path_ = documents_dir.Append(suggested_name);
621 } else { 648 } else {
622 initial_path_ = suggested_name; 649 initial_path_ = suggested_name;
623 } 650 }
624 } 651 }
625 } 652 }
626 653
627 void FileSystemChooseEntryFunction::FilesSelected( 654 void FileSystemChooseEntryFunction::FilesSelected(
628 const std::vector<base::FilePath>& paths) { 655 const std::vector<base::FilePath>& paths) {
629 DCHECK(!paths.empty()); 656 DCHECK(!paths.empty());
630 file_system_api::SetLastChooseEntryDirectory( 657 base::FilePath last_choose_directory;
631 ExtensionPrefs::Get(profile()), GetExtension()->id(), paths[0].DirName()); 658 if (is_directory_) {
659 last_choose_directory = paths[0];
660 } else {
661 last_choose_directory = paths[0].DirName();
662 }
663 file_system_api::SetLastChooseEntryDirectory(ExtensionPrefs::Get(profile()),
664 GetExtension()->id(),
665 last_choose_directory);
632 if (app_file_handler_util::HasFileSystemWritePermission(extension_)) { 666 if (app_file_handler_util::HasFileSystemWritePermission(extension_)) {
633 CheckWritableFiles(paths); 667 CheckWritableFiles(paths);
634 return; 668 return;
635 } 669 }
636 670
637 // Don't need to check the file, it's for reading. 671 // Don't need to check the file, it's for reading.
638 RegisterFileSystemsAndSendResponse(paths); 672 RegisterFileSystemsAndSendResponse(paths);
639 } 673 }
640 674
641 void FileSystemChooseEntryFunction::FileSelectionCanceled() { 675 void FileSystemChooseEntryFunction::FileSelectionCanceled() {
(...skipping 83 matching lines...)
725 } else if (options->type == file_system::CHOOSE_ENTRY_TYPE_SAVEFILE) { 759 } else if (options->type == file_system::CHOOSE_ENTRY_TYPE_SAVEFILE) {
726 if (!app_file_handler_util::HasFileSystemWritePermission(extension_)) { 760 if (!app_file_handler_util::HasFileSystemWritePermission(extension_)) {
727 error_ = kRequiresFileSystemWriteError; 761 error_ = kRequiresFileSystemWriteError;
728 return false; 762 return false;
729 } 763 }
730 if (multiple_) { 764 if (multiple_) {
731 error_ = kMultipleUnsupportedError; 765 error_ = kMultipleUnsupportedError;
732 return false; 766 return false;
733 } 767 }
734 picker_type = ui::SelectFileDialog::SELECT_SAVEAS_FILE; 768 picker_type = ui::SelectFileDialog::SELECT_SAVEAS_FILE;
769 } else if (options->type == file_system::CHOOSE_ENTRY_TYPE_OPENDIRECTORY) {
770 is_directory_ = true;
771 if (!extension_->HasAPIPermission(APIPermission::kFileSystemDirectory)) {
772 error_ = kRequiresFileSystemDirectoryError;
773 return false;
774 }
775 if (multiple_) {
776 error_ = kMultipleUnsupportedError;
777 return false;
778 }
779 picker_type = ui::SelectFileDialog::SELECT_FOLDER;
735 } 780 }
736 781
737 base::FilePath::StringType suggested_extension; 782 base::FilePath::StringType suggested_extension;
738 BuildSuggestion(options->suggested_name.get(), &suggested_name, 783 BuildSuggestion(options->suggested_name.get(), &suggested_name,
739 &suggested_extension); 784 &suggested_extension);
740 785
741 BuildFileTypeInfo(&file_type_info, suggested_extension, 786 BuildFileTypeInfo(&file_type_info, suggested_extension,
742 options->accepts.get(), options->accepts_all_types.get()); 787 options->accepts.get(), options->accepts_all_types.get());
743 } 788 }
744 789
(...skipping 15 matching lines...)
760 &FileSystemChooseEntryFunction::ShowPicker, this, file_type_info, 805 &FileSystemChooseEntryFunction::ShowPicker, this, file_type_info,
761 picker_type)); 806 picker_type));
762 return true; 807 return true;
763 } 808 }
764 809
765 bool FileSystemRetainEntryFunction::RunImpl() { 810 bool FileSystemRetainEntryFunction::RunImpl() {
766 std::string entry_id; 811 std::string entry_id;
767 EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &entry_id)); 812 EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &entry_id));
768 SavedFilesService* saved_files_service = SavedFilesService::Get(profile()); 813 SavedFilesService* saved_files_service = SavedFilesService::Get(profile());
769 // Add the file to the retain list if it is not already on there. 814 // Add the file to the retain list if it is not already on there.
770 if (!saved_files_service->IsRegistered(extension_->id(), entry_id) && 815 if (!saved_files_service->IsRegistered(extension_->id(), entry_id)) {
771 !RetainFileEntry(entry_id)) { 816 std::string filesystem_name;
772 return false; 817 std::string filesystem_path;
818 EXTENSION_FUNCTION_VALIDATE(args_->GetString(1, &filesystem_name));
819 EXTENSION_FUNCTION_VALIDATE(args_->GetString(2, &filesystem_path));
820 if (!ValidateFileEntryAndGetPath(filesystem_name,
821 filesystem_path,
822 render_view_host_,
823 &path_,
824 &error_)) {
825 return false;
826 }
827 content::BrowserThread::PostTaskAndReply(
828 content::BrowserThread::FILE,
829 FROM_HERE,
830 base::Bind(&FileSystemRetainEntryFunction::SetIsDirectoryOnFileThread,
831 this),
832 base::Bind(
833 &FileSystemRetainEntryFunction::RetainFileEntry, this, entry_id));
834 return true;
773 } 835 }
774 saved_files_service->EnqueueFileEntry(extension_->id(), entry_id); 836 saved_files_service->EnqueueFileEntry(extension_->id(), entry_id);
837 SendResponse(true);
775 return true; 838 return true;
776 } 839 }
777 840
778 bool FileSystemRetainEntryFunction::RetainFileEntry( 841 void FileSystemRetainEntryFunction::RetainFileEntry(
779 const std::string& entry_id) { 842 const std::string& entry_id) {
780 std::string filesystem_name; 843 SavedFilesService* saved_files_service = SavedFilesService::Get(profile());
781 std::string filesystem_path; 844 saved_files_service->RegisterFileEntry(
782 EXTENSION_FUNCTION_VALIDATE(args_->GetString(1, &filesystem_name)); 845 extension_->id(), entry_id, path_, is_directory_);
783 EXTENSION_FUNCTION_VALIDATE(args_->GetString(2, &filesystem_path)); 846 saved_files_service->EnqueueFileEntry(extension_->id(), entry_id);
784 base::FilePath path; 847 SendResponse(true);
785 if (!ValidateFileEntryAndGetPath(filesystem_name, 848 }
786 filesystem_path, 849
787 render_view_host_, 850 void FileSystemRetainEntryFunction::SetIsDirectoryOnFileThread() {
788 &path, 851 if (base::DirectoryExists(path_)) {
789 &error_)) { 852 is_directory_ = true;
790 return false;
791 } 853 }
792
793 SavedFilesService::Get(profile())->RegisterFileEntry(
794 extension_->id(), entry_id, path);
795 return true;
796 } 854 }
797 855
798 bool FileSystemIsRestorableFunction::RunImpl() { 856 bool FileSystemIsRestorableFunction::RunImpl() {
799 std::string entry_id; 857 std::string entry_id;
800 EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &entry_id)); 858 EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &entry_id));
801 SetResult(new base::FundamentalValue(SavedFilesService::Get( 859 SetResult(new base::FundamentalValue(SavedFilesService::Get(
802 profile())->IsRegistered(extension_->id(), entry_id))); 860 profile())->IsRegistered(extension_->id(), entry_id)));
803 return true; 861 return true;
804 } 862 }
805 863
806 bool FileSystemRestoreEntryFunction::RunImpl() { 864 bool FileSystemRestoreEntryFunction::RunImpl() {
807 std::string entry_id; 865 std::string entry_id;
808 bool needs_new_entry; 866 bool needs_new_entry;
809 EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &entry_id)); 867 EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &entry_id));
810 EXTENSION_FUNCTION_VALIDATE(args_->GetBoolean(1, &needs_new_entry)); 868 EXTENSION_FUNCTION_VALIDATE(args_->GetBoolean(1, &needs_new_entry));
811 const SavedFileEntry* file_entry = SavedFilesService::Get( 869 const SavedFileEntry* file_entry = SavedFilesService::Get(
812 profile())->GetFileEntry(extension_->id(), entry_id); 870 profile())->GetFileEntry(extension_->id(), entry_id);
813 if (!file_entry) { 871 if (!file_entry) {
814 error_ = kUnknownIdError; 872 error_ = kUnknownIdError;
815 return false; 873 return false;
816 } 874 }
817 875
818 SavedFilesService::Get(profile())->EnqueueFileEntry( 876 SavedFilesService::Get(profile())->EnqueueFileEntry(
819 extension_->id(), entry_id); 877 extension_->id(), entry_id);
820 878
821 // Only create a new file entry if the renderer requests one. 879 // Only create a new file entry if the renderer requests one.
822 // |needs_new_entry| will be false if the renderer already has an Entry for 880 // |needs_new_entry| will be false if the renderer already has an Entry for
823 // |entry_id|. 881 // |entry_id|.
824 if (needs_new_entry) { 882 if (needs_new_entry) {
883 is_directory_ = file_entry->is_directory;
825 CreateResponse(); 884 CreateResponse();
826 AddEntryToResponse(file_entry->path, file_entry->id); 885 AddEntryToResponse(file_entry->path, file_entry->id);
827 } 886 }
828 SendResponse(true); 887 SendResponse(true);
829 return true; 888 return true;
830 } 889 }
831 890
832 } // namespace extensions 891 } // namespace extensions
OLDNEW

Powered by Google App Engine