From dc65a2f2b80743c004b96ed75eef8747e19e4ee8 Mon Sep 17 00:00:00 2001 From: Romain Chardiny Date: Sun, 21 May 2023 17:48:52 +0200 Subject: [PATCH] unzip: Add option to list files of an archive --- Userland/Libraries/LibArchive/Zip.cpp | 4 ++-- Userland/Libraries/LibArchive/Zip.h | 2 +- Userland/Utilities/unzip.cpp | 25 +++++++++++++++++++++++++ 3 files changed, 28 insertions(+), 3 deletions(-) diff --git a/Userland/Libraries/LibArchive/Zip.cpp b/Userland/Libraries/LibArchive/Zip.cpp index 33e5e6e70e..8b71b5ee5f 100644 --- a/Userland/Libraries/LibArchive/Zip.cpp +++ b/Userland/Libraries/LibArchive/Zip.cpp @@ -75,7 +75,7 @@ Optional Zip::try_create(ReadonlyBytes buffer) }; } -ErrorOr Zip::for_each_member(Function callback) +ErrorOr Zip::for_each_member(Function(ZipMember const&)> callback) { size_t member_offset = m_members_start_offset; for (size_t i = 0; i < m_member_count; i++) { @@ -94,7 +94,7 @@ ErrorOr Zip::for_each_member(Function member.modification_date = central_directory_record.modification_date; member.is_directory = central_directory_record.external_attributes & zip_directory_external_attribute || member.name.bytes_as_string_view().ends_with('/'); // FIXME: better directory detection - if (callback(member) == IterationDecision::Break) + if (TRY(callback(member)) == IterationDecision::Break) return false; member_offset += central_directory_record.size(); diff --git a/Userland/Libraries/LibArchive/Zip.h b/Userland/Libraries/LibArchive/Zip.h index 453464d1dc..f87c6dca8f 100644 --- a/Userland/Libraries/LibArchive/Zip.h +++ b/Userland/Libraries/LibArchive/Zip.h @@ -253,7 +253,7 @@ struct ZipMember { class Zip { public: static Optional try_create(ReadonlyBytes buffer); - ErrorOr for_each_member(Function); + ErrorOr for_each_member(Function(ZipMember const&)>); private: static bool find_end_of_central_directory_offset(ReadonlyBytes, size_t& offset); diff --git a/Userland/Utilities/unzip.cpp b/Userland/Utilities/unzip.cpp index 95833bb6dd..3d6d8f9794 100644 --- a/Userland/Utilities/unzip.cpp +++ b/Userland/Utilities/unzip.cpp @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -104,10 +105,12 @@ ErrorOr serenity_main(Main::Arguments arguments) { StringView zip_file_path; bool quiet { false }; + bool list_files { false }; StringView output_directory_path; Vector file_filters; Core::ArgsParser args_parser; + args_parser.add_option(list_files, "Only list files in the archive", "list", 'l'); args_parser.add_option(output_directory_path, "Directory to receive the archive content", "output-directory", 'd', "path"); args_parser.add_option(quiet, "Be less verbose", "quiet", 'q'); args_parser.add_positional_argument(zip_file_path, "File to unzip", "path", Core::ArgsParser::Required::Yes); @@ -140,6 +143,28 @@ ErrorOr serenity_main(Main::Arguments arguments) TRY(Core::System::chdir(output_directory_path)); } + if (list_files) { + outln(" Length Date Time Name"); + outln("--------- ---------- -------- ----"); + u32 members_count = 0; + u64 total_size = 0; + TRY(zip_file->for_each_member([&](auto zip_member) -> ErrorOr { + members_count++; + + auto time = time_from_packed_dos(zip_member.modification_date, zip_member.modification_time); + auto time_str = TRY(Core::DateTime::from_timestamp(time.seconds_since_epoch()).to_string()); + + total_size += zip_member.uncompressed_size; + + outln("{:>9} {} {}", zip_member.uncompressed_size, time_str, zip_member.name); + + return IterationDecision::Continue; + })); + outln("--------- ----"); + outln("{:>9} {} files", total_size, members_count); + return 0; + } + Vector zip_directories; auto success = TRY(zip_file->for_each_member([&](auto zip_member) {