Utilities: Merge the gunzip utility with gzip

Now both /bin/zcat and /bin/gunzip are symlinks to /bin/gzip, and we
essentially running it in decompression mode through these symlinks.

This ensures we don't maintain 2 versions of code to decompress Gzipped
data anymore, and handle the use case of gzipped-streaming input only
once in the codebase.
This commit is contained in:
Liav A 2023-09-02 00:04:54 +03:00 committed by Andrew Kaster
parent cd486a7040
commit 5b34b4af14
9 changed files with 55 additions and 97 deletions

1
.github/CODEOWNERS vendored
View File

@ -35,7 +35,6 @@
/Userland/Services/SQLServer @trflynn89
/Userland/Services/WebDriver @trflynn89
/Userland/Shell @alimpfard
/Userland/Utilities/gunzip.cpp @timschumi
/Userland/Utilities/gzip.cpp @timschumi
/Userland/Utilities/lzcat.cpp @timschumi
/Userland/Utilities/readelf.cpp @BertalanD

View File

@ -1,22 +0,0 @@
## Name
gunzip
## Synopsis
```sh
$ gunzip [--keep] [--stdout] <FILE...>
```
## Options
* `-k`, `--keep`: Keep (don't delete) input files
* `-c`, `--stdout`: Write to stdout, keep original files unchanged
## Arguments
* `FILE`: File to decompress
## See also
* [`gzip`(1)](help://man/1/gzip)
* [`tar`(1)](help://man/1/tar)

View File

@ -0,0 +1 @@
gzip.md

View File

@ -1,11 +1,13 @@
## Name
gzip
gzip, gunzip, zcat
## Synopsis
```sh
$ gzip [--keep] [--stdout] [--decompress] <FILES...>
$ gunzip [--keep] [--stdout] <FILES...>
$ zcat <FILES...>
```
## Options
@ -19,5 +21,4 @@ $ gzip [--keep] [--stdout] [--decompress] <FILES...>
* `FILES`: Files
## See also
* [`gunzip`(1)](help://man/1/gunzip)
* [`tar`(1)](help://man/1/tar)

View File

@ -40,5 +40,4 @@ Archive: archive.unzip
## See also
* [`zip`(1)](help://man/1/zip)
* [`gunzip`(1)](help://man/1/gunzip)
* [`tar`(1)](help://man/1/tar)

View File

@ -0,0 +1 @@
gzip.md

View File

@ -558,7 +558,6 @@ if (BUILD_LAGOM)
endif()
lagom_utility(gml-format SOURCES ../../Userland/Utilities/gml-format.cpp LIBS LibGUI LibMain)
lagom_utility(gunzip SOURCES ../../Userland/Utilities/gunzip.cpp LIBS LibCompress LibMain)
lagom_utility(gzip SOURCES ../../Userland/Utilities/gzip.cpp LIBS LibCompress LibMain)
# Work around bug in JetBrains distributed CMake 3.27.2 where this causes infinite recursion in

View File

@ -2,7 +2,7 @@ file(GLOB CMD_SOURCES CONFIGURE_DEPENDS "*.cpp")
list(APPEND SPECIAL_TARGETS test install)
list(APPEND REQUIRED_TARGETS
arp base64 basename cat chmod chown clear comm cp cut date dd df diff dirname dmesg du echo env expr false
file find grep groups gunzip head host hostname id ifconfig kill killall ln logout ls mkdir mount mv network-settings nproc
file find grep groups head host hostname id ifconfig kill killall ln logout ls mkdir mount mv network-settings nproc
patch pgrep pidof ping pkill pmap ps readlink realpath reboot rm rmdir sed route seq shutdown sleep sort stat stty su tail test
touch tr true umount uname uniq uptime w wc which whoami xargs yes
)
@ -70,7 +70,8 @@ endif()
install(CODE "file(CREATE_LINK grep ${CMAKE_INSTALL_PREFIX}/bin/egrep SYMBOLIC)")
install(CODE "file(CREATE_LINK grep ${CMAKE_INSTALL_PREFIX}/bin/fgrep SYMBOLIC)")
install(CODE "file(CREATE_LINK grep ${CMAKE_INSTALL_PREFIX}/bin/rgrep SYMBOLIC)")
install(CODE "file(CREATE_LINK gunzip ${CMAKE_INSTALL_PREFIX}/bin/zcat SYMBOLIC)")
install(CODE "file(CREATE_LINK gzip ${CMAKE_INSTALL_PREFIX}/bin/gunzip SYMBOLIC)")
install(CODE "file(CREATE_LINK gzip ${CMAKE_INSTALL_PREFIX}/bin/zcat SYMBOLIC)")
target_link_libraries(abench PRIVATE LibAudio LibFileSystem)
target_link_libraries(aconv PRIVATE LibAudio LibFileSystem)
@ -99,7 +100,6 @@ target_link_libraries(functrace PRIVATE LibDebug LibELF LibX86)
target_link_libraries(glsl-compiler PRIVATE LibGLSL)
target_link_libraries(gml-format PRIVATE LibGUI)
target_link_libraries(grep PRIVATE LibFileSystem LibRegex LibURL)
target_link_libraries(gunzip PRIVATE LibCompress)
target_link_libraries(gzip PRIVATE LibCompress)
target_link_libraries(headless-browser PRIVATE LibCrypto LibFileSystem LibGemini LibGfx LibHTTP LibImageDecoderClient LibTLS LibWeb LibWebView LibWebSocket LibIPC LibJS LibDiff LibURL)
target_link_libraries(icc PRIVATE LibGfx LibVideo LibURL)

View File

@ -1,55 +0,0 @@
/*
* Copyright (c) 2020, the SerenityOS developers.
* Copyright (c) 2023, Liav A. <liavalb@hotmail.co.il>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <LibCompress/Gzip.h>
#include <LibCore/ArgsParser.h>
#include <LibCore/File.h>
#include <LibCore/System.h>
#include <LibMain/Main.h>
#include <unistd.h>
ErrorOr<int> serenity_main(Main::Arguments args)
{
Vector<StringView> filenames;
bool keep_input_files { false };
bool write_to_stdout { false };
Core::ArgsParser args_parser;
// NOTE: If the user run this program via the /bin/zcat symlink,
// then emulate gzip decompression to stdout.
if (args.argc > 0 && args.strings[0] == "zcat"sv) {
write_to_stdout = true;
} else {
args_parser.add_option(keep_input_files, "Keep (don't delete) input files", "keep", 'k');
args_parser.add_option(write_to_stdout, "Write to stdout, keep original files unchanged", "stdout", 'c');
}
args_parser.add_positional_argument(filenames, "File to decompress", "FILE");
args_parser.parse(args);
if (write_to_stdout)
keep_input_files = true;
for (auto filename : filenames) {
ByteString input_filename;
ByteString output_filename;
if (filename.ends_with(".gz"sv)) {
input_filename = filename;
output_filename = filename.substring_view(0, filename.length() - 3);
} else {
input_filename = ByteString::formatted("{}.gz", filename);
output_filename = filename;
}
auto output_stream = write_to_stdout ? TRY(Core::File::standard_output()) : TRY(Core::File::open(output_filename, Core::File::OpenMode::Write));
TRY(Compress::GzipDecompressor::decompress_file(input_filename, move(output_stream)));
if (!keep_input_files)
TRY(Core::System::unlink(input_filename));
}
return 0;
}

View File

@ -4,6 +4,8 @@
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <AK/ByteString.h>
#include <AK/LexicalPath.h>
#include <LibCompress/Gzip.h>
#include <LibCore/ArgsParser.h>
#include <LibCore/File.h>
@ -23,34 +25,67 @@ ErrorOr<int> serenity_main(Main::Arguments arguments)
args_parser.add_option(keep_input_files, "Keep (don't delete) input files", "keep", 'k');
args_parser.add_option(write_to_stdout, "Write to stdout, keep original files unchanged", "stdout", 'c');
args_parser.add_option(decompress, "Decompress", "decompress", 'd');
args_parser.add_positional_argument(filenames, "Files", "FILES");
args_parser.add_positional_argument(filenames, "Files", "FILES", Core::ArgsParser::Required::No);
args_parser.parse(arguments);
auto program_name = LexicalPath::basename(arguments.strings[0]);
// NOTE: If the user run this program via the /bin/zcat or /bin/gunzip symlink,
// then emulate gzip decompression.
if (program_name == "zcat"sv || program_name == "gunzip"sv)
decompress = true;
if (program_name == "zcat"sv)
write_to_stdout = true;
if (filenames.is_empty()) {
filenames.append("-"sv);
write_to_stdout = true;
}
if (write_to_stdout)
keep_input_files = true;
for (auto const& input_filename : filenames) {
ByteString output_filename;
if (decompress) {
OwnPtr<Stream> output_stream;
if (write_to_stdout) {
output_stream = TRY(Core::File::standard_output());
} else if (decompress) {
if (!input_filename.ends_with(".gz"sv)) {
warnln("unknown suffix for: {}, skipping", input_filename);
continue;
}
output_filename = input_filename.substring_view(0, input_filename.length() - ".gz"sv.length());
auto output_filename = input_filename.substring_view(0, input_filename.length() - ".gz"sv.length());
output_stream = TRY(Core::File::open(output_filename, Core::File::OpenMode::Write));
} else {
output_filename = ByteString::formatted("{}.gz", input_filename);
auto output_filename = ByteString::formatted("{}.gz", input_filename);
output_stream = TRY(Core::File::open(output_filename, Core::File::OpenMode::Write));
}
auto output_stream = write_to_stdout ? TRY(Core::File::standard_output()) : TRY(Core::File::open(output_filename, Core::File::OpenMode::Write));
VERIFY(output_stream);
if (decompress)
TRY(Compress::GzipDecompressor::decompress_file(input_filename, move(output_stream)));
else
TRY(Compress::GzipCompressor::compress_file(input_filename, move(output_stream)));
NonnullOwnPtr<Core::File> input_file = TRY(Core::File::open_file_or_standard_stream(input_filename, Core::File::OpenMode::Read));
if (!keep_input_files) {
// Buffer reads, which yields a significant performance improvement.
NonnullOwnPtr<Stream> input_stream = TRY(Core::InputBufferedFile::create(move(input_file), 1 * MiB));
if (decompress) {
input_stream = TRY(try_make<Compress::GzipDecompressor>(move(input_stream)));
} else {
output_stream = TRY(try_make<Compress::GzipCompressor>(output_stream.release_nonnull()));
}
auto buffer = TRY(ByteBuffer::create_uninitialized(1 * MiB));
while (!input_stream->is_eof()) {
auto span = TRY(input_stream->read_some(buffer));
TRY(output_stream->write_until_depleted(span));
}
if (!keep_input_files)
TRY(Core::System::unlink(input_filename));
}
}
return 0;