diff options
author | Andreas Kling <kling@serenityos.org> | 2021-01-12 12:17:30 +0100 |
---|---|---|
committer | Andreas Kling <kling@serenityos.org> | 2021-01-12 12:17:46 +0100 |
commit | 13d7c09125f8eec703d0a43a9a87fc8aa08f7319 (patch) | |
tree | 70fd643c429cea5c1f9362c2674511d17a53f3b5 /Userland/Libraries/LibTar | |
parent | dc28c07fa526841e05e16161c74a6c23984f1dd5 (diff) | |
download | serenity-13d7c09125f8eec703d0a43a9a87fc8aa08f7319.zip |
Libraries: Move to Userland/Libraries/
Diffstat (limited to 'Userland/Libraries/LibTar')
-rw-r--r-- | Userland/Libraries/LibTar/CMakeLists.txt | 6 | ||||
-rw-r--r-- | Userland/Libraries/LibTar/Tar.h | 107 | ||||
-rw-r--r-- | Userland/Libraries/LibTar/TarStream.cpp | 133 | ||||
-rw-r--r-- | Userland/Libraries/LibTar/TarStream.h | 72 |
4 files changed, 318 insertions, 0 deletions
diff --git a/Userland/Libraries/LibTar/CMakeLists.txt b/Userland/Libraries/LibTar/CMakeLists.txt new file mode 100644 index 0000000000..94c0420438 --- /dev/null +++ b/Userland/Libraries/LibTar/CMakeLists.txt @@ -0,0 +1,6 @@ +set(SOURCES + TarStream.cpp +) + +serenity_lib(LibTar tar) +target_link_libraries(LibTar LibCore) diff --git a/Userland/Libraries/LibTar/Tar.h b/Userland/Libraries/LibTar/Tar.h new file mode 100644 index 0000000000..70f1764344 --- /dev/null +++ b/Userland/Libraries/LibTar/Tar.h @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2020, Peter Elliott <pelliott@ualberta.ca> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#include <AK/StringView.h> +#include <sys/types.h> + +namespace Tar { + +enum FileType { + NormalFile = '0', + AlternateNormalFile = '\0', + HardLink = '1', + SymLink = '2', + CharacterSpecialFile = '3', + BlockSpecialFile = '4', + Directory = '5', + FIFO = '6', + ContiguousFile = '7', + GlobalExtendedHeader = 'g', + ExtendedHeader = 'x' +}; + +constexpr size_t block_size = 512; +constexpr const char* ustar_magic = "ustar "; + +class Header { +public: + // FIXME: support ustar filename prefix + const StringView file_name() const { return m_file_name; } + mode_t mode() const { return get_tar_field(m_mode); } + uid_t uid() const { return get_tar_field(m_uid); } + gid_t gid() const { return get_tar_field(m_gid); } + // FIXME: support 2001-star size encoding + size_t size() const { return get_tar_field(m_size); } + 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 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: + char m_file_name[100]; + char m_mode[8]; + char m_uid[8]; + char m_gid[8]; + char m_size[12]; + char m_timestamp[12]; + char m_checksum[8]; + char m_type_flag; + char m_link_name[100]; + char m_magic[6]; + char m_version[2]; + char m_owner_name[32]; + char m_group_name[32]; + char m_major[8]; + char m_minor[8]; + char m_prefix[155]; + + template<size_t N> + static size_t get_tar_field(const char (&field)[N]); +}; + +template<size_t N> +size_t Header::get_tar_field(const char (&field)[N]) +{ + size_t value = 0; + for (size_t i = 0; i < N; ++i) { + if (field[i] == 0) + break; + + ASSERT(field[i] >= '0' && field[i] <= '7'); + value *= 8; + value += field[i] - '0'; + } + return value; +} + +} diff --git a/Userland/Libraries/LibTar/TarStream.cpp b/Userland/Libraries/LibTar/TarStream.cpp new file mode 100644 index 0000000000..533a01e932 --- /dev/null +++ b/Userland/Libraries/LibTar/TarStream.cpp @@ -0,0 +1,133 @@ +/* + * Copyright (c) 2020, Peter Elliott <pelliott@ualberta.ca> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <AK/LogStream.h> +#include <LibTar/TarStream.h> + +namespace Tar { +TarFileStream::TarFileStream(TarStream& tar_stream) + : m_tar_stream(tar_stream) + , m_generation(tar_stream.m_generation) +{ +} + +size_t TarFileStream::read(Bytes bytes) +{ + // verify that the stream has not advanced + ASSERT(m_tar_stream.m_generation == m_generation); + + if (has_any_error()) + return 0; + + auto to_read = min(bytes.size(), m_tar_stream.header().size() - m_tar_stream.m_file_offset); + + auto nread = m_tar_stream.m_stream.read(bytes.trim(to_read)); + m_tar_stream.m_file_offset += nread; + return nread; +} + +bool TarFileStream::unreliable_eof() const +{ + // verify that the stream has not advanced + ASSERT(m_tar_stream.m_generation == m_generation); + + return m_tar_stream.m_stream.unreliable_eof() + || m_tar_stream.m_file_offset >= m_tar_stream.header().size(); +} + +bool TarFileStream::read_or_error(Bytes bytes) +{ + // verify that the stream has not advanced + ASSERT(m_tar_stream.m_generation == m_generation); + + if (read(bytes) < bytes.size()) { + set_fatal_error(); + return false; + } + + return true; +} + +bool TarFileStream::discard_or_error(size_t count) +{ + // verify that the stream has not advanced + ASSERT(m_tar_stream.m_generation == m_generation); + + if (count > m_tar_stream.header().size() - m_tar_stream.m_file_offset) { + return false; + } + m_tar_stream.m_file_offset += count; + return m_tar_stream.m_stream.discard_or_error(count); +} + +TarStream::TarStream(InputStream& stream) + : m_stream(stream) +{ + if (!m_stream.read_or_error(Bytes(&m_header, sizeof(m_header)))) { + m_finished = true; + return; + } + ASSERT(m_stream.discard_or_error(block_size - sizeof(Header))); +} + +static constexpr unsigned long block_ceiling(unsigned long offset) +{ + return block_size * (1 + ((offset - 1) / block_size)); +} + +void TarStream::advance() +{ + if (m_finished) + return; + + m_generation++; + ASSERT(m_stream.discard_or_error(block_ceiling(m_header.size()) - m_file_offset)); + m_file_offset = 0; + + if (!m_stream.read_or_error(Bytes(&m_header, sizeof(m_header)))) { + m_finished = true; + return; + } + if (!valid()) { + m_finished = true; + return; + } + + 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); + return TarFileStream(*this); +} + +} diff --git a/Userland/Libraries/LibTar/TarStream.h b/Userland/Libraries/LibTar/TarStream.h new file mode 100644 index 0000000000..adcf0cdb5f --- /dev/null +++ b/Userland/Libraries/LibTar/TarStream.h @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2020, Peter Elliott <pelliott@ualberta.ca> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#include <AK/Span.h> +#include <AK/Stream.h> +#include <LibTar/Tar.h> + +namespace Tar { + +class TarStream; + +class TarFileStream : public InputStream { +public: + size_t read(Bytes) override; + bool unreliable_eof() const override; + + bool read_or_error(Bytes) override; + bool discard_or_error(size_t count) override; + +private: + TarFileStream(TarStream& stream); + TarStream& m_tar_stream; + int m_generation; + + friend class TarStream; +}; + +class TarStream { +public: + TarStream(InputStream&); + void advance(); + bool finished() const { return m_finished; } + bool valid() const; + const Header& header() const { return m_header; } + TarFileStream file_contents(); + +private: + Header m_header; + InputStream& m_stream; + unsigned long m_file_offset { 0 }; + int m_generation { 0 }; + bool m_finished { false }; + + friend class TarFileStream; +}; + +} |