| OLD | NEW |
| 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...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 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...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 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...) Expand all Loading... |
| 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...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 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...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 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...) Expand all Loading... |
| 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 |
| OLD | NEW |