From 255da9b02bdd821d9b25182e943e2102c358263a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mi=C8=9Bca=20Dumitru?= Date: Sun, 21 Feb 2021 02:56:28 +0200 Subject: [PATCH] FileManager: Use newly introduced LibCore file management helpers Most of the functions under FileUtils were removed, except those which dealt with file deletion, as they spawned MessageBoxes for errors, as such, those functions were written in terms of Core::File::remove. --- .../FileManager/DirectoryView.cpp | 4 +- .../Applications/FileManager/FileUtils.cpp | 212 +----------------- Userland/Applications/FileManager/FileUtils.h | 7 - Userland/Applications/FileManager/main.cpp | 13 +- 4 files changed, 20 insertions(+), 216 deletions(-) diff --git a/Userland/Applications/FileManager/DirectoryView.cpp b/Userland/Applications/FileManager/DirectoryView.cpp index 02c411b36d..2dbcd68b54 100644 --- a/Userland/Applications/FileManager/DirectoryView.cpp +++ b/Userland/Applications/FileManager/DirectoryView.cpp @@ -580,8 +580,8 @@ void DirectoryView::handle_drop(const GUI::ModelIndex& index, const GUI::DropEve if (url_to_copy.path() == new_path) continue; - if (!FileUtils::copy_file_or_directory(url_to_copy.path(), new_path)) { - auto error_message = String::formatted("Could not copy {} into {}.", url_to_copy.to_string(), new_path); + if (auto result = Core::File::copy_file_or_directory(new_path, url_to_copy.path()); result.is_error()) { + auto error_message = String::formatted("Could not copy {} into {}: {}", url_to_copy.to_string(), new_path, result.error().error_code); GUI::MessageBox::show(window(), error_message, "File Manager", GUI::MessageBox::Type::Error); } else { had_accepted_drop = true; diff --git a/Userland/Applications/FileManager/FileUtils.cpp b/Userland/Applications/FileManager/FileUtils.cpp index 76d2ee0079..c9639916db 100644 --- a/Userland/Applications/FileManager/FileUtils.cpp +++ b/Userland/Applications/FileManager/FileUtils.cpp @@ -26,13 +26,9 @@ #include "FileUtils.h" #include -#include -#include #include #include #include -#include -#include #include #include @@ -48,22 +44,22 @@ void delete_path(const String& path, GUI::Window* parent_window) GUI::MessageBox::Type::Error); } - if (S_ISDIR(st.st_mode)) { - String error_path; - int error = FileUtils::delete_directory(path, error_path); + bool is_directory = S_ISDIR(st.st_mode); + auto result = Core::File::remove(path, Core::File::RecursionMode::Allowed, false); - if (error) { + if (result.is_error()) { + auto& error = result.error(); + if (is_directory) { GUI::MessageBox::show(parent_window, - String::formatted("Failed to delete directory \"{}\": {}", error_path, strerror(error)), + String::formatted("Failed to delete directory \"{}\": {}", error.file, error.error_code), + "Delete failed", + GUI::MessageBox::Type::Error); + } else { + GUI::MessageBox::show(parent_window, + String::formatted("Failed to delete file \"{}\": {}", error.file, error.error_code), "Delete failed", GUI::MessageBox::Type::Error); } - } else if (unlink(path.characters()) < 0) { - int saved_errno = errno; - GUI::MessageBox::show(parent_window, - String::formatted("unlink(\"{}\") failed: {}", path, strerror(saved_errno)), - "Delete failed", - GUI::MessageBox::Type::Error); } } @@ -91,190 +87,4 @@ void delete_paths(const Vector& paths, bool should_confirm, GUI::Window* } } -int delete_directory(String directory, String& file_that_caused_error) -{ - Core::DirIterator iterator(directory, Core::DirIterator::SkipDots); - if (iterator.has_error()) { - file_that_caused_error = directory; - return -1; - } - - while (iterator.has_next()) { - auto file_to_delete = String::formatted("{}/{}", directory, iterator.next_path()); - struct stat st; - - if (lstat(file_to_delete.characters(), &st)) { - file_that_caused_error = file_to_delete; - return errno; - } - - if (S_ISDIR(st.st_mode)) { - if (delete_directory(file_to_delete, file_to_delete)) { - file_that_caused_error = file_to_delete; - return errno; - } - } else if (unlink(file_to_delete.characters())) { - file_that_caused_error = file_to_delete; - return errno; - } - } - - if (rmdir(directory.characters())) { - file_that_caused_error = directory; - return errno; - } - - return 0; -} - -bool copy_file_or_directory(const String& src_path, const String& dst_path) -{ - int duplicate_count = 0; - while (access(get_duplicate_name(dst_path, duplicate_count).characters(), F_OK) == 0) { - ++duplicate_count; - } - if (duplicate_count != 0) { - return copy_file_or_directory(src_path, get_duplicate_name(dst_path, duplicate_count)); - } - - auto source_or_error = Core::File::open(src_path, Core::IODevice::ReadOnly); - if (source_or_error.is_error()) - return false; - - auto& source = *source_or_error.value(); - - struct stat src_stat; - int rc = fstat(source.fd(), &src_stat); - if (rc < 0) - return false; - - if (source.is_directory()) - return copy_directory(src_path, dst_path, src_stat); - - return copy_file(dst_path, src_stat, source); -} - -bool copy_directory(const String& src_path, const String& dst_path, const struct stat& src_stat) -{ - int rc = mkdir(dst_path.characters(), 0755); - if (rc < 0) { - return false; - } - Core::DirIterator di(src_path, Core::DirIterator::SkipDots); - if (di.has_error()) { - return false; - } - while (di.has_next()) { - String filename = di.next_path(); - bool is_copied = copy_file_or_directory( - String::formatted("{}/{}", src_path, filename), - String::formatted("{}/{}", dst_path, filename)); - if (!is_copied) { - return false; - } - } - - auto my_umask = umask(0); - umask(my_umask); - rc = chmod(dst_path.characters(), src_stat.st_mode & ~my_umask); - if (rc < 0) { - return false; - } - return true; -} - -bool copy_file(const String& dst_path, const struct stat& src_stat, Core::File& source) -{ - int dst_fd = creat(dst_path.characters(), 0666); - if (dst_fd < 0) { - if (errno != EISDIR) { - return false; - } - auto dst_dir_path = String::formatted("{}/{}", dst_path, LexicalPath(source.filename()).basename()); - dst_fd = creat(dst_dir_path.characters(), 0666); - if (dst_fd < 0) { - return false; - } - } - - ScopeGuard close_fd_guard([dst_fd]() { close(dst_fd); }); - - if (src_stat.st_size > 0) { - if (ftruncate(dst_fd, src_stat.st_size) < 0) { - perror("cp: ftruncate"); - return false; - } - } - - for (;;) { - char buffer[32768]; - ssize_t nread = read(source.fd(), buffer, sizeof(buffer)); - if (nread < 0) { - return false; - } - if (nread == 0) - break; - ssize_t remaining_to_write = nread; - char* bufptr = buffer; - while (remaining_to_write) { - ssize_t nwritten = write(dst_fd, bufptr, remaining_to_write); - if (nwritten < 0) { - return false; - } - assert(nwritten > 0); - remaining_to_write -= nwritten; - bufptr += nwritten; - } - } - - auto my_umask = umask(0); - umask(my_umask); - int rc = fchmod(dst_fd, src_stat.st_mode & ~my_umask); - if (rc < 0) { - return false; - } - - return true; -} - -bool link_file(const String& src_path, const String& dst_path) -{ - int duplicate_count = 0; - while (access(get_duplicate_name(dst_path, duplicate_count).characters(), F_OK) == 0) { - ++duplicate_count; - } - if (duplicate_count != 0) { - return link_file(src_path, get_duplicate_name(dst_path, duplicate_count)); - } - int rc = symlink(src_path.characters(), dst_path.characters()); - if (rc < 0) { - return false; - } - - return true; -} - -String get_duplicate_name(const String& path, int duplicate_count) -{ - if (duplicate_count == 0) { - return path; - } - LexicalPath lexical_path(path); - StringBuilder duplicated_name; - duplicated_name.append('/'); - for (size_t i = 0; i < lexical_path.parts().size() - 1; ++i) { - duplicated_name.appendff("{}/", lexical_path.parts()[i]); - } - auto prev_duplicate_tag = String::formatted("({})", duplicate_count); - auto title = lexical_path.title(); - if (title.ends_with(prev_duplicate_tag)) { - // remove the previous duplicate tag "(n)" so we can add a new tag. - title = title.substring(0, title.length() - prev_duplicate_tag.length()); - } - duplicated_name.appendff("{} ({})", lexical_path.title(), duplicate_count); - if (!lexical_path.extension().is_empty()) { - duplicated_name.appendff(".{}", lexical_path.extension()); - } - return duplicated_name.build(); -} } diff --git a/Userland/Applications/FileManager/FileUtils.h b/Userland/Applications/FileManager/FileUtils.h index fcf6b483ac..314da67a70 100644 --- a/Userland/Applications/FileManager/FileUtils.h +++ b/Userland/Applications/FileManager/FileUtils.h @@ -40,11 +40,4 @@ enum class FileOperation { void delete_path(const String&, GUI::Window*); void delete_paths(const Vector&, bool should_confirm, GUI::Window*); -int delete_directory(String directory, String& file_that_caused_error); -bool copy_file_or_directory(const String& src_path, const String& dst_path); -String get_duplicate_name(const String& path, int duplicate_count); -bool copy_file(const String& dst_path, const struct stat& src_stat, Core::File&); -bool copy_directory(const String& src_path, const String& dst_path, const struct stat& src_stat); -bool link_file(const String& src_path, const String& dst_path); - } diff --git a/Userland/Applications/FileManager/main.cpp b/Userland/Applications/FileManager/main.cpp index 80819571f8..568ef53f94 100644 --- a/Userland/Applications/FileManager/main.cpp +++ b/Userland/Applications/FileManager/main.cpp @@ -33,6 +33,7 @@ #include #include #include +#include #include #include #include @@ -171,8 +172,8 @@ void do_paste(const String& target_directory, GUI::Window* window) } auto new_path = String::formatted("{}/{}", target_directory, url.basename()); - if (!FileUtils::copy_file_or_directory(url.path(), new_path)) { - auto error_message = String::formatted("Could not paste {}.", url.path()); + if (auto result = Core::File::copy_file_or_directory(new_path, url.path()); result.is_error()) { + auto error_message = String::formatted("Could not paste '{}': {}", url.path(), result.error().error_code); GUI::MessageBox::show(window, error_message, "File Manager", GUI::MessageBox::Type::Error); } else if (should_delete_src) { FileUtils::delete_path(url.path(), window); @@ -184,8 +185,8 @@ void do_create_link(const Vector& selected_file_paths, GUI::Window* wind { auto path = selected_file_paths.first(); auto destination = String::formatted("{}/{}", Core::StandardPaths::desktop_directory(), LexicalPath { path }.basename()); - if (!FileUtils::link_file(path, destination)) { - GUI::MessageBox::show(window, "Could not create desktop shortcut", "File Manager", + if (auto result = Core::File::link_file(destination, path); result.is_error()) { + GUI::MessageBox::show(window, String::formatted("Could not create desktop shortcut:\n{}", result.error()), "File Manager", GUI::MessageBox::Type::Error); } } @@ -984,8 +985,8 @@ int run_in_windowed_mode(RefPtr config, String initial_locatio if (url_to_copy.path() == new_path) continue; - if (!FileUtils::copy_file_or_directory(url_to_copy.path(), new_path)) { - auto error_message = String::formatted("Could not copy {} into {}.", url_to_copy.to_string(), new_path); + if (auto result = Core::File::copy_file_or_directory(url_to_copy.path(), new_path); result.is_error()) { + auto error_message = String::formatted("Could not copy {} into {}:\n {}", url_to_copy.to_string(), new_path, result.error().error_code); GUI::MessageBox::show(window, error_message, "File Manager", GUI::MessageBox::Type::Error); } else { had_accepted_copy = true;