FileUtils.cpp 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  1. /*
  2. * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
  3. * Copyright (c) 2021, Sam Atkins <atkinssj@gmail.com>
  4. *
  5. * SPDX-License-Identifier: BSD-2-Clause
  6. */
  7. #include "FileUtils.h"
  8. #include "FileOperationProgressWidget.h"
  9. #include <AK/LexicalPath.h>
  10. #include <LibCore/DirIterator.h>
  11. #include <LibCore/File.h>
  12. #include <LibGUI/MessageBox.h>
  13. #include <sys/stat.h>
  14. #include <unistd.h>
  15. namespace FileManager {
  16. HashTable<NonnullRefPtr<GUI::Window>> file_operation_windows;
  17. void delete_path(String const& path, GUI::Window* parent_window)
  18. {
  19. struct stat st;
  20. if (lstat(path.characters(), &st)) {
  21. GUI::MessageBox::show(parent_window,
  22. String::formatted("lstat({}) failed: {}", path, strerror(errno)),
  23. "Delete failed",
  24. GUI::MessageBox::Type::Error);
  25. }
  26. bool is_directory = S_ISDIR(st.st_mode);
  27. auto result = Core::File::remove(path, Core::File::RecursionMode::Allowed, false);
  28. if (result.is_error()) {
  29. auto& error = result.error();
  30. if (is_directory) {
  31. GUI::MessageBox::show(parent_window,
  32. String::formatted("Failed to delete directory \"{}\": {}", error.file, error.error_code),
  33. "Delete failed",
  34. GUI::MessageBox::Type::Error);
  35. } else {
  36. GUI::MessageBox::show(parent_window,
  37. String::formatted("Failed to delete file \"{}\": {}", error.file, error.error_code),
  38. "Delete failed",
  39. GUI::MessageBox::Type::Error);
  40. }
  41. }
  42. }
  43. void delete_paths(Vector<String> const& paths, bool should_confirm, GUI::Window* parent_window)
  44. {
  45. String message;
  46. if (paths.size() == 1) {
  47. message = String::formatted("Really delete {}?", LexicalPath::basename(paths[0]));
  48. } else {
  49. message = String::formatted("Really delete {} files?", paths.size());
  50. }
  51. if (should_confirm) {
  52. auto result = GUI::MessageBox::show(parent_window,
  53. message,
  54. "Confirm deletion",
  55. GUI::MessageBox::Type::Warning,
  56. GUI::MessageBox::InputType::OKCancel);
  57. if (result == GUI::MessageBox::ExecCancel)
  58. return;
  59. }
  60. for (auto& path : paths) {
  61. delete_path(path, parent_window);
  62. }
  63. }
  64. void run_file_operation(FileOperation operation, Vector<String> const& sources, String const& destination, GUI::Window* parent_window)
  65. {
  66. int pipe_fds[2];
  67. if (pipe(pipe_fds) < 0) {
  68. perror("pipe");
  69. VERIFY_NOT_REACHED();
  70. }
  71. pid_t child_pid = fork();
  72. if (child_pid < 0) {
  73. perror("fork");
  74. VERIFY_NOT_REACHED();
  75. }
  76. if (!child_pid) {
  77. if (close(pipe_fds[0]) < 0) {
  78. perror("close");
  79. _exit(1);
  80. }
  81. if (dup2(pipe_fds[1], STDOUT_FILENO) < 0) {
  82. perror("dup2");
  83. _exit(1);
  84. }
  85. Vector<char const*> file_operation_args;
  86. file_operation_args.append("/bin/FileOperation");
  87. switch (operation) {
  88. case FileOperation::Copy:
  89. file_operation_args.append("Copy");
  90. break;
  91. case FileOperation::Cut:
  92. file_operation_args.append("Move");
  93. break;
  94. default:
  95. VERIFY_NOT_REACHED();
  96. }
  97. for (auto& source : sources)
  98. file_operation_args.append(source.characters());
  99. file_operation_args.append(destination.characters());
  100. file_operation_args.append(nullptr);
  101. if (execvp(file_operation_args.first(), const_cast<char**>(file_operation_args.data())) < 0) {
  102. perror("execvp");
  103. _exit(1);
  104. }
  105. VERIFY_NOT_REACHED();
  106. } else {
  107. if (close(pipe_fds[1]) < 0) {
  108. perror("close");
  109. _exit(1);
  110. }
  111. }
  112. auto window = GUI::Window::construct();
  113. file_operation_windows.set(window);
  114. auto pipe_input_file = Core::File::construct();
  115. pipe_input_file->open(pipe_fds[0], Core::OpenMode::ReadOnly, Core::File::ShouldCloseFileDescriptor::Yes);
  116. window->set_title("Copying Files...");
  117. window->set_main_widget<FileOperationProgressWidget>(pipe_input_file);
  118. window->resize(320, 190);
  119. if (parent_window)
  120. window->center_within(*parent_window);
  121. window->show();
  122. }
  123. }