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_, |
| 318 is_directory_, |
315 base::Bind(&FileSystemEntryFunction::RegisterFileSystemsAndSendResponse, | 319 base::Bind(&FileSystemEntryFunction::RegisterFileSystemsAndSendResponse, |
316 this, | 320 this, |
317 paths), | 321 paths), |
318 base::Bind(&FileSystemEntryFunction::HandleWritableFileError, this)); | 322 base::Bind(&FileSystemEntryFunction::HandleWritableFileError, this)); |
319 } | 323 } |
320 | 324 |
321 void FileSystemEntryFunction::RegisterFileSystemsAndSendResponse( | 325 void FileSystemEntryFunction::RegisterFileSystemsAndSendResponse( |
322 const std::vector<base::FilePath>& paths) { | 326 const std::vector<base::FilePath>& paths) { |
323 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); | 327 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); |
324 | 328 |
(...skipping 16 matching lines...) Expand all Loading... |
341 | 345 |
342 void FileSystemEntryFunction::AddEntryToResponse( | 346 void FileSystemEntryFunction::AddEntryToResponse( |
343 const base::FilePath& path, | 347 const base::FilePath& path, |
344 const std::string& id_override) { | 348 const std::string& id_override) { |
345 DCHECK(response_); | 349 DCHECK(response_); |
346 extensions::app_file_handler_util::GrantedFileEntry file_entry = | 350 extensions::app_file_handler_util::GrantedFileEntry file_entry = |
347 extensions::app_file_handler_util::CreateFileEntry( | 351 extensions::app_file_handler_util::CreateFileEntry( |
348 profile(), | 352 profile(), |
349 GetExtension(), | 353 GetExtension(), |
350 render_view_host_->GetProcess()->GetID(), | 354 render_view_host_->GetProcess()->GetID(), |
351 path); | 355 path, |
| 356 is_directory_); |
352 base::ListValue* entries; | 357 base::ListValue* entries; |
353 bool success = response_->GetList("entries", &entries); | 358 bool success = response_->GetList("entries", &entries); |
354 DCHECK(success); | 359 DCHECK(success); |
355 | 360 |
356 base::DictionaryValue* entry = new base::DictionaryValue(); | 361 base::DictionaryValue* entry = new base::DictionaryValue(); |
357 entry->SetString("fileSystemId", file_entry.filesystem_id); | 362 entry->SetString("fileSystemId", file_entry.filesystem_id); |
358 entry->SetString("baseName", file_entry.registered_name); | 363 entry->SetString("baseName", file_entry.registered_name); |
359 if (id_override.empty()) | 364 if (id_override.empty()) |
360 entry->SetString("id", file_entry.id); | 365 entry->SetString("id", file_entry.id); |
361 else | 366 else |
362 entry->SetString("id", id_override); | 367 entry->SetString("id", id_override); |
| 368 entry->SetBoolean("isDirectory", is_directory_); |
363 entries->Append(entry); | 369 entries->Append(entry); |
364 } | 370 } |
365 | 371 |
366 void FileSystemEntryFunction::HandleWritableFileError( | 372 void FileSystemEntryFunction::HandleWritableFileError( |
367 const base::FilePath& error_path) { | 373 const base::FilePath& error_path) { |
368 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); | 374 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); |
369 error_ = base::StringPrintf(kWritableFileErrorFormat, | 375 error_ = base::StringPrintf(kWritableFileErrorFormat, |
370 error_path.BaseName().AsUTF8Unsafe().c_str()); | 376 error_path.BaseName().AsUTF8Unsafe().c_str()); |
371 SendResponse(false); | 377 SendResponse(false); |
372 } | 378 } |
373 | 379 |
374 bool FileSystemGetWritableEntryFunction::RunImpl() { | 380 bool FileSystemGetWritableEntryFunction::RunImpl() { |
375 std::string filesystem_name; | 381 std::string filesystem_name; |
376 std::string filesystem_path; | 382 std::string filesystem_path; |
377 EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &filesystem_name)); | 383 EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &filesystem_name)); |
378 EXTENSION_FUNCTION_VALIDATE(args_->GetString(1, &filesystem_path)); | 384 EXTENSION_FUNCTION_VALIDATE(args_->GetString(1, &filesystem_path)); |
379 | 385 |
380 if (!app_file_handler_util::HasFileSystemWritePermission(extension_)) { | 386 if (!app_file_handler_util::HasFileSystemWritePermission(extension_)) { |
381 error_ = kRequiresFileSystemWriteError; | 387 error_ = kRequiresFileSystemWriteError; |
382 return false; | 388 return false; |
383 } | 389 } |
384 | 390 |
385 base::FilePath path; | |
386 if (!ValidateFileEntryAndGetPath(filesystem_name, filesystem_path, | 391 if (!ValidateFileEntryAndGetPath(filesystem_name, filesystem_path, |
387 render_view_host_, &path, &error_)) | 392 render_view_host_, &path_, &error_)) |
388 return false; | 393 return false; |
389 | 394 |
390 std::vector<base::FilePath> paths; | 395 content::BrowserThread::PostTaskAndReply( |
391 paths.push_back(path); | 396 content::BrowserThread::FILE, |
392 CheckWritableFiles(paths); | 397 FROM_HERE, |
| 398 base::Bind( |
| 399 &FileSystemGetWritableEntryFunction::SetIsDirectoryOnFileThread, |
| 400 this), |
| 401 base::Bind( |
| 402 &FileSystemGetWritableEntryFunction::CheckPermissionAndSendResponse, |
| 403 this)); |
393 return true; | 404 return true; |
394 } | 405 } |
395 | 406 |
| 407 void FileSystemGetWritableEntryFunction::CheckPermissionAndSendResponse() { |
| 408 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); |
| 409 if (is_directory_ && |
| 410 !extension_->HasAPIPermission(APIPermission::kFileSystemDirectory)) { |
| 411 error_ = kRequiresFileSystemDirectoryError; |
| 412 SendResponse(false); |
| 413 } |
| 414 std::vector<base::FilePath> paths; |
| 415 paths.push_back(path_); |
| 416 CheckWritableFiles(paths); |
| 417 } |
| 418 |
| 419 void FileSystemGetWritableEntryFunction::SetIsDirectoryOnFileThread() { |
| 420 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE)); |
| 421 if (base::DirectoryExists(path_)) { |
| 422 is_directory_ = true; |
| 423 } |
| 424 } |
| 425 |
396 bool FileSystemIsWritableEntryFunction::RunImpl() { | 426 bool FileSystemIsWritableEntryFunction::RunImpl() { |
397 std::string filesystem_name; | 427 std::string filesystem_name; |
398 std::string filesystem_path; | 428 std::string filesystem_path; |
399 EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &filesystem_name)); | 429 EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &filesystem_name)); |
400 EXTENSION_FUNCTION_VALIDATE(args_->GetString(1, &filesystem_path)); | 430 EXTENSION_FUNCTION_VALIDATE(args_->GetString(1, &filesystem_path)); |
401 | 431 |
402 std::string filesystem_id; | 432 std::string filesystem_id; |
403 if (!fileapi::CrackIsolatedFileSystemName(filesystem_name, &filesystem_id)) { | 433 if (!fileapi::CrackIsolatedFileSystemName(filesystem_name, &filesystem_id)) { |
404 error_ = kInvalidParameters; | 434 error_ = kInvalidParameters; |
405 return false; | 435 return false; |
(...skipping 214 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
620 initial_path_ = documents_dir.Append(suggested_name); | 650 initial_path_ = documents_dir.Append(suggested_name); |
621 } else { | 651 } else { |
622 initial_path_ = suggested_name; | 652 initial_path_ = suggested_name; |
623 } | 653 } |
624 } | 654 } |
625 } | 655 } |
626 | 656 |
627 void FileSystemChooseEntryFunction::FilesSelected( | 657 void FileSystemChooseEntryFunction::FilesSelected( |
628 const std::vector<base::FilePath>& paths) { | 658 const std::vector<base::FilePath>& paths) { |
629 DCHECK(!paths.empty()); | 659 DCHECK(!paths.empty()); |
630 file_system_api::SetLastChooseEntryDirectory( | 660 base::FilePath last_choose_directory; |
631 ExtensionPrefs::Get(profile()), GetExtension()->id(), paths[0].DirName()); | 661 if (is_directory_) { |
| 662 last_choose_directory = paths[0]; |
| 663 } else { |
| 664 last_choose_directory = paths[0].DirName(); |
| 665 } |
| 666 file_system_api::SetLastChooseEntryDirectory(ExtensionPrefs::Get(profile()), |
| 667 GetExtension()->id(), |
| 668 last_choose_directory); |
632 if (app_file_handler_util::HasFileSystemWritePermission(extension_)) { | 669 if (app_file_handler_util::HasFileSystemWritePermission(extension_)) { |
633 CheckWritableFiles(paths); | 670 CheckWritableFiles(paths); |
634 return; | 671 return; |
635 } | 672 } |
636 | 673 |
637 // Don't need to check the file, it's for reading. | 674 // Don't need to check the file, it's for reading. |
638 RegisterFileSystemsAndSendResponse(paths); | 675 RegisterFileSystemsAndSendResponse(paths); |
639 } | 676 } |
640 | 677 |
641 void FileSystemChooseEntryFunction::FileSelectionCanceled() { | 678 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) { | 762 } else if (options->type == file_system::CHOOSE_ENTRY_TYPE_SAVEFILE) { |
726 if (!app_file_handler_util::HasFileSystemWritePermission(extension_)) { | 763 if (!app_file_handler_util::HasFileSystemWritePermission(extension_)) { |
727 error_ = kRequiresFileSystemWriteError; | 764 error_ = kRequiresFileSystemWriteError; |
728 return false; | 765 return false; |
729 } | 766 } |
730 if (multiple_) { | 767 if (multiple_) { |
731 error_ = kMultipleUnsupportedError; | 768 error_ = kMultipleUnsupportedError; |
732 return false; | 769 return false; |
733 } | 770 } |
734 picker_type = ui::SelectFileDialog::SELECT_SAVEAS_FILE; | 771 picker_type = ui::SelectFileDialog::SELECT_SAVEAS_FILE; |
| 772 } else if (options->type == file_system::CHOOSE_ENTRY_TYPE_OPENDIRECTORY) { |
| 773 is_directory_ = true; |
| 774 if (!extension_->HasAPIPermission(APIPermission::kFileSystemDirectory)) { |
| 775 error_ = kRequiresFileSystemDirectoryError; |
| 776 return false; |
| 777 } |
| 778 if (multiple_) { |
| 779 error_ = kMultipleUnsupportedError; |
| 780 return false; |
| 781 } |
| 782 picker_type = ui::SelectFileDialog::SELECT_FOLDER; |
735 } | 783 } |
736 | 784 |
737 base::FilePath::StringType suggested_extension; | 785 base::FilePath::StringType suggested_extension; |
738 BuildSuggestion(options->suggested_name.get(), &suggested_name, | 786 BuildSuggestion(options->suggested_name.get(), &suggested_name, |
739 &suggested_extension); | 787 &suggested_extension); |
740 | 788 |
741 BuildFileTypeInfo(&file_type_info, suggested_extension, | 789 BuildFileTypeInfo(&file_type_info, suggested_extension, |
742 options->accepts.get(), options->accepts_all_types.get()); | 790 options->accepts.get(), options->accepts_all_types.get()); |
743 } | 791 } |
744 | 792 |
(...skipping 15 matching lines...) Expand all Loading... |
760 &FileSystemChooseEntryFunction::ShowPicker, this, file_type_info, | 808 &FileSystemChooseEntryFunction::ShowPicker, this, file_type_info, |
761 picker_type)); | 809 picker_type)); |
762 return true; | 810 return true; |
763 } | 811 } |
764 | 812 |
765 bool FileSystemRetainEntryFunction::RunImpl() { | 813 bool FileSystemRetainEntryFunction::RunImpl() { |
766 std::string entry_id; | 814 std::string entry_id; |
767 EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &entry_id)); | 815 EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &entry_id)); |
768 SavedFilesService* saved_files_service = SavedFilesService::Get(profile()); | 816 SavedFilesService* saved_files_service = SavedFilesService::Get(profile()); |
769 // Add the file to the retain list if it is not already on there. | 817 // Add the file to the retain list if it is not already on there. |
770 if (!saved_files_service->IsRegistered(extension_->id(), entry_id) && | 818 if (!saved_files_service->IsRegistered(extension_->id(), entry_id)) { |
771 !RetainFileEntry(entry_id)) { | 819 std::string filesystem_name; |
772 return false; | 820 std::string filesystem_path; |
| 821 EXTENSION_FUNCTION_VALIDATE(args_->GetString(1, &filesystem_name)); |
| 822 EXTENSION_FUNCTION_VALIDATE(args_->GetString(2, &filesystem_path)); |
| 823 if (!ValidateFileEntryAndGetPath(filesystem_name, |
| 824 filesystem_path, |
| 825 render_view_host_, |
| 826 &path_, |
| 827 &error_)) { |
| 828 return false; |
| 829 } |
| 830 |
| 831 content::BrowserThread::PostTaskAndReply( |
| 832 content::BrowserThread::FILE, |
| 833 FROM_HERE, |
| 834 base::Bind(&FileSystemRetainEntryFunction::SetIsDirectoryOnFileThread, |
| 835 this), |
| 836 base::Bind( |
| 837 &FileSystemRetainEntryFunction::RetainFileEntry, this, entry_id)); |
| 838 return true; |
773 } | 839 } |
| 840 |
774 saved_files_service->EnqueueFileEntry(extension_->id(), entry_id); | 841 saved_files_service->EnqueueFileEntry(extension_->id(), entry_id); |
| 842 SendResponse(true); |
775 return true; | 843 return true; |
776 } | 844 } |
777 | 845 |
778 bool FileSystemRetainEntryFunction::RetainFileEntry( | 846 void FileSystemRetainEntryFunction::RetainFileEntry( |
779 const std::string& entry_id) { | 847 const std::string& entry_id) { |
780 std::string filesystem_name; | 848 SavedFilesService* saved_files_service = SavedFilesService::Get(profile()); |
781 std::string filesystem_path; | 849 saved_files_service->RegisterFileEntry( |
782 EXTENSION_FUNCTION_VALIDATE(args_->GetString(1, &filesystem_name)); | 850 extension_->id(), entry_id, path_, is_directory_); |
783 EXTENSION_FUNCTION_VALIDATE(args_->GetString(2, &filesystem_path)); | 851 saved_files_service->EnqueueFileEntry(extension_->id(), entry_id); |
784 base::FilePath path; | 852 SendResponse(true); |
785 if (!ValidateFileEntryAndGetPath(filesystem_name, | 853 } |
786 filesystem_path, | 854 |
787 render_view_host_, | 855 void FileSystemRetainEntryFunction::SetIsDirectoryOnFileThread() { |
788 &path, | 856 if (base::DirectoryExists(path_)) { |
789 &error_)) { | 857 is_directory_ = true; |
790 return false; | |
791 } | 858 } |
792 | |
793 SavedFilesService::Get(profile())->RegisterFileEntry( | |
794 extension_->id(), entry_id, path); | |
795 return true; | |
796 } | 859 } |
797 | 860 |
798 bool FileSystemIsRestorableFunction::RunImpl() { | 861 bool FileSystemIsRestorableFunction::RunImpl() { |
799 std::string entry_id; | 862 std::string entry_id; |
800 EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &entry_id)); | 863 EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &entry_id)); |
801 SetResult(new base::FundamentalValue(SavedFilesService::Get( | 864 SetResult(new base::FundamentalValue(SavedFilesService::Get( |
802 profile())->IsRegistered(extension_->id(), entry_id))); | 865 profile())->IsRegistered(extension_->id(), entry_id))); |
803 return true; | 866 return true; |
804 } | 867 } |
805 | 868 |
806 bool FileSystemRestoreEntryFunction::RunImpl() { | 869 bool FileSystemRestoreEntryFunction::RunImpl() { |
807 std::string entry_id; | 870 std::string entry_id; |
808 bool needs_new_entry; | 871 bool needs_new_entry; |
809 EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &entry_id)); | 872 EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &entry_id)); |
810 EXTENSION_FUNCTION_VALIDATE(args_->GetBoolean(1, &needs_new_entry)); | 873 EXTENSION_FUNCTION_VALIDATE(args_->GetBoolean(1, &needs_new_entry)); |
811 const SavedFileEntry* file_entry = SavedFilesService::Get( | 874 const SavedFileEntry* file_entry = SavedFilesService::Get( |
812 profile())->GetFileEntry(extension_->id(), entry_id); | 875 profile())->GetFileEntry(extension_->id(), entry_id); |
813 if (!file_entry) { | 876 if (!file_entry) { |
814 error_ = kUnknownIdError; | 877 error_ = kUnknownIdError; |
815 return false; | 878 return false; |
816 } | 879 } |
817 | 880 |
818 SavedFilesService::Get(profile())->EnqueueFileEntry( | 881 SavedFilesService::Get(profile())->EnqueueFileEntry( |
819 extension_->id(), entry_id); | 882 extension_->id(), entry_id); |
820 | 883 |
821 // Only create a new file entry if the renderer requests one. | 884 // 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 | 885 // |needs_new_entry| will be false if the renderer already has an Entry for |
823 // |entry_id|. | 886 // |entry_id|. |
824 if (needs_new_entry) { | 887 if (needs_new_entry) { |
| 888 is_directory_ = file_entry->is_directory; |
825 CreateResponse(); | 889 CreateResponse(); |
826 AddEntryToResponse(file_entry->path, file_entry->id); | 890 AddEntryToResponse(file_entry->path, file_entry->id); |
827 } | 891 } |
828 SendResponse(true); | 892 SendResponse(true); |
829 return true; | 893 return true; |
830 } | 894 } |
831 | 895 |
832 } // namespace extensions | 896 } // namespace extensions |
OLD | NEW |