summaryrefslogtreecommitdiff
path: root/Userland
diff options
context:
space:
mode:
authorTim Schumacher <timschumi@gmx.de>2022-11-29 01:01:13 +0100
committerAndreas Kling <kling@serenityos.org>2022-11-30 08:03:31 +0100
commit714f0c3dce22dc7218567b925b4af78e6b0f3928 (patch)
tree38e24a6fd8f4e404389e9649e81b77302b86cbf3 /Userland
parentcb48b9bc309a16f50d8be7370a56c127c7615369 (diff)
downloadserenity-714f0c3dce22dc7218567b925b4af78e6b0f3928.zip
LibArchive: Implement proper support for Tar file end markers
Previously this was handled implicitly, as our implementation of Tar would just stop processing input as soon as it found something invalid. However, since we now error out as soon as something is found to be wrong, we require proper handling for zero blocks, which aren't actually fatal.
Diffstat (limited to 'Userland')
-rw-r--r--Userland/Libraries/LibArchive/Tar.cpp10
-rw-r--r--Userland/Libraries/LibArchive/Tar.h1
-rw-r--r--Userland/Libraries/LibArchive/TarStream.cpp26
-rw-r--r--Userland/Libraries/LibArchive/TarStream.h3
4 files changed, 33 insertions, 7 deletions
diff --git a/Userland/Libraries/LibArchive/Tar.cpp b/Userland/Libraries/LibArchive/Tar.cpp
index a5758d93af..a91fc1fdff 100644
--- a/Userland/Libraries/LibArchive/Tar.cpp
+++ b/Userland/Libraries/LibArchive/Tar.cpp
@@ -30,6 +30,16 @@ void TarFileHeader::calculate_checksum()
VERIFY(String::formatted("{:06o}", expected_checksum()).copy_characters_to_buffer(m_checksum, sizeof(m_checksum)));
}
+bool TarFileHeader::is_zero_block() const
+{
+ u8 const* buffer = reinterpret_cast<u8 const*>(this);
+ for (size_t i = 0; i < sizeof(TarFileHeader); ++i) {
+ if (buffer[i] != 0)
+ return false;
+ }
+ return true;
+}
+
bool TarFileHeader::content_is_like_extended_header() const
{
return type_flag() == TarFileType::ExtendedHeader || type_flag() == TarFileType::GlobalExtendedHeader;
diff --git a/Userland/Libraries/LibArchive/Tar.h b/Userland/Libraries/LibArchive/Tar.h
index 6b9ddd86a1..6600be810c 100644
--- a/Userland/Libraries/LibArchive/Tar.h
+++ b/Userland/Libraries/LibArchive/Tar.h
@@ -129,6 +129,7 @@ public:
unsigned expected_checksum() const;
void calculate_checksum();
+ bool is_zero_block() const;
bool content_is_like_extended_header() const;
void set_filename_and_prefix(StringView filename);
diff --git a/Userland/Libraries/LibArchive/TarStream.cpp b/Userland/Libraries/LibArchive/TarStream.cpp
index 87928ffac8..7810d0bc52 100644
--- a/Userland/Libraries/LibArchive/TarStream.cpp
+++ b/Userland/Libraries/LibArchive/TarStream.cpp
@@ -90,16 +90,30 @@ ErrorOr<void> TarInputStream::advance()
ErrorOr<void> TarInputStream::load_next_header()
{
- auto header_span = TRY(m_stream->read(Bytes(&m_header, sizeof(m_header))));
- if (header_span.size() != sizeof(m_header))
- return Error::from_string_literal("Failed to read the entire header");
+ size_t number_of_consecutive_zero_blocks = 0;
+ while (true) {
+ auto header_span = TRY(m_stream->read(Bytes(&m_header, sizeof(m_header))));
+ if (header_span.size() != sizeof(m_header))
+ return Error::from_string_literal("Failed to read the entire header");
+
+ // Discard the rest of the header block.
+ TRY(m_stream->discard(block_size - sizeof(TarFileHeader)));
+
+ if (!header().is_zero_block())
+ break;
+
+ number_of_consecutive_zero_blocks++;
+
+ // Two zero blocks in a row marks the end of the archive.
+ if (number_of_consecutive_zero_blocks >= 2) {
+ m_found_end_of_archive = true;
+ return {};
+ }
+ }
if (!TRY(valid()))
return Error::from_string_literal("Header has an invalid magic or checksum");
- // Discard the rest of the header block.
- TRY(m_stream->discard(block_size - sizeof(TarFileHeader)));
-
return {};
}
diff --git a/Userland/Libraries/LibArchive/TarStream.h b/Userland/Libraries/LibArchive/TarStream.h
index 46fd6e44ef..d779ea55fe 100644
--- a/Userland/Libraries/LibArchive/TarStream.h
+++ b/Userland/Libraries/LibArchive/TarStream.h
@@ -35,7 +35,7 @@ class TarInputStream {
public:
static ErrorOr<NonnullOwnPtr<TarInputStream>> construct(NonnullOwnPtr<Core::Stream::Stream>);
ErrorOr<void> advance();
- bool finished() const { return m_stream->is_eof(); }
+ bool finished() const { return m_found_end_of_archive || m_stream->is_eof(); }
ErrorOr<bool> valid() const;
TarFileHeader const& header() const { return m_header; }
TarFileStream file_contents();
@@ -51,6 +51,7 @@ private:
NonnullOwnPtr<Core::Stream::Stream> m_stream;
unsigned long m_file_offset { 0 };
int m_generation { 0 };
+ bool m_found_end_of_archive { false };
friend class TarFileStream;
};