diff --git a/Libraries/LibTar/Tar.h b/Libraries/LibTar/Tar.h index 34d4cde05d..70f1764344 100644 --- a/Libraries/LibTar/Tar.h +++ b/Libraries/LibTar/Tar.h @@ -46,6 +46,7 @@ enum FileType { }; constexpr size_t block_size = 512; +constexpr const char* ustar_magic = "ustar "; class Header { public: @@ -59,14 +60,14 @@ public: time_t timestamp() const { return get_tar_field(m_timestamp); } FileType type_flag() const { return FileType(m_type_flag); } const StringView link_name() const { return m_link_name; } - const StringView magic() const { return m_magic; } - const StringView version() const { return m_version; } + const StringView magic() const { return StringView(m_magic, sizeof(m_magic)); } + const StringView version() const { return StringView(m_version, sizeof(m_version)); } const StringView owner_name() const { return m_owner_name; } const StringView group_name() const { return m_group_name; } int major() const { return get_tar_field(m_major); } int minor() const { return get_tar_field(m_minor); } - //private: +private: char m_file_name[100]; char m_mode[8]; char m_uid[8]; diff --git a/Libraries/LibTar/TarStream.cpp b/Libraries/LibTar/TarStream.cpp index 983e37faad..533a01e932 100644 --- a/Libraries/LibTar/TarStream.cpp +++ b/Libraries/LibTar/TarStream.cpp @@ -111,7 +111,7 @@ void TarStream::advance() m_finished = true; return; } - if (m_header.magic() == "") { + if (!valid()) { m_finished = true; return; } @@ -119,6 +119,11 @@ void TarStream::advance() ASSERT(m_stream.discard_or_error(block_size - sizeof(Header))); } +bool TarStream::valid() const +{ + return header().magic() == ustar_magic; +} + TarFileStream TarStream::file_contents() { ASSERT(!m_finished); diff --git a/Libraries/LibTar/TarStream.h b/Libraries/LibTar/TarStream.h index 56e1bab93c..adcf0cdb5f 100644 --- a/Libraries/LibTar/TarStream.h +++ b/Libraries/LibTar/TarStream.h @@ -55,6 +55,7 @@ public: TarStream(InputStream&); void advance(); bool finished() const { return m_finished; } + bool valid() const; const Header& header() const { return m_header; } TarFileStream file_contents(); diff --git a/Userland/CMakeLists.txt b/Userland/CMakeLists.txt index 34283b24c3..9d2a361e7d 100644 --- a/Userland/CMakeLists.txt +++ b/Userland/CMakeLists.txt @@ -35,7 +35,7 @@ target_link_libraries(passwd LibCrypt) target_link_libraries(paste LibGUI) target_link_libraries(pro LibProtocol) target_link_libraries(su LibCrypt) -target_link_libraries(tar LibTar) +target_link_libraries(tar LibTar LibCompress) target_link_libraries(test-crypto LibCrypto LibTLS LibLine) target_link_libraries(test-compress LibCompress) target_link_libraries(test-js LibJS LibLine LibCore) diff --git a/Userland/tar.cpp b/Userland/tar.cpp index 83669e33cd..7a9bc3dd59 100644 --- a/Userland/tar.cpp +++ b/Userland/tar.cpp @@ -26,6 +26,7 @@ #include #include +#include #include #include #include @@ -41,6 +42,7 @@ int main(int argc, char** argv) bool extract = false; bool list = false; bool verbose = false; + bool gzip = false; const char* archive_file = nullptr; Vector paths; @@ -49,6 +51,7 @@ int main(int argc, char** argv) args_parser.add_option(extract, "Extract archive", "extract", 'x'); args_parser.add_option(list, "List contents", "list", 't'); args_parser.add_option(verbose, "Print paths", "verbose", 'v'); + args_parser.add_option(gzip, "compress or uncompress file using gzip", "gzip", 'z'); args_parser.add_option(archive_file, "Archive file", "file", 'f', "FILE"); args_parser.add_positional_argument(paths, "Paths", "PATHS", Core::ArgsParser::Required::No); args_parser.parse(argc, argv); @@ -69,8 +72,17 @@ int main(int argc, char** argv) } file = maybe_file.value(); } - Core::InputFileStream input_stream(file); - Tar::TarStream tar_stream(input_stream); + + Core::InputFileStream file_stream(file); + Compress::GzipDecompressor gzip_stream(file_stream); + + InputStream& file_input_stream = file_stream; + InputStream& gzip_input_stream = gzip_stream; + Tar::TarStream tar_stream((gzip) ? gzip_input_stream : file_input_stream); + if (!tar_stream.valid()) { + warn() << "the provided file is not a well-formatted ustar file"; + return 1; + } for (; !tar_stream.finished(); tar_stream.advance()) { if (list || verbose) out() << tar_stream.header().file_name(); @@ -112,7 +124,7 @@ int main(int argc, char** argv) } } } - input_stream.close(); + file_stream.close(); return 0; }