From 6bd3ff85a501e87b5cd1d8b2a1c7927b58ae1334 Mon Sep 17 00:00:00 2001 From: Thomas Klaehn Date: Wed, 9 Jun 2021 07:45:02 +0200 Subject: [PATCH] Tar handler --- .vscode/settings.json | 16 ++++++ Makefile | 2 +- inc/Buffer.h | 43 ++++++++++++++++ inc/ringbuffer.h | 24 --------- src/TarHandler.cc | 111 ++++++++++++++++++++++++++++++++++++++++++ src/TarHandler.h | 53 ++++++++++++++++++++ src/main.cc | 47 ++++++++++++------ src/ringbuffer.cc | 39 --------------- 8 files changed, 255 insertions(+), 80 deletions(-) create mode 100644 .vscode/settings.json create mode 100644 inc/Buffer.h delete mode 100644 inc/ringbuffer.h create mode 100644 src/TarHandler.cc create mode 100644 src/TarHandler.h delete mode 100644 src/ringbuffer.cc diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..f924103 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,16 @@ +{ + "files.associations": { + "array": "cpp", + "deque": "cpp", + "string": "cpp", + "unordered_map": "cpp", + "vector": "cpp", + "iterator": "cpp", + "memory_resource": "cpp", + "optional": "cpp", + "string_view": "cpp", + "initializer_list": "cpp", + "type_traits": "cpp", + "utility": "cpp" + } +} \ No newline at end of file diff --git a/Makefile b/Makefile index 8ee189c..4ab0661 100644 --- a/Makefile +++ b/Makefile @@ -9,7 +9,7 @@ CXXFLAGS += -pedantic CXXFLAGS += -pedantic-errors CXXFLAGS += -ffunction-sections -fdata-sections CXXFLAGS += -fno-implicit-inline-templates -CXXFLAGS += -Iinc +CXXFLAGS += -Isrc LD_LIBS := -lc -lgcc -lpthread diff --git a/inc/Buffer.h b/inc/Buffer.h new file mode 100644 index 0000000..0e70270 --- /dev/null +++ b/inc/Buffer.h @@ -0,0 +1,43 @@ +#ifndef __INC_BUFFER_H__ +#define __INC_BUFFER_H__ + +template +class Buffer + : std::array +{ + typedef std::array ArrayT; + typedef typename ArrayT::reference reference; + typedef typename ArrayT::const_reference const_reference; + typedef typename ArrayT::size_type size_type; + typedef typename ArrayT::value_type value_type; + typedef typename ArrayT::iterator iterator; + typedef typename ArrayT::const_iterator const_iterator; + +public: + Buffer() : length(0) {} + + constexpr reference front() noexcept { return ArrayT::front(); } + constexpr reference back() noexcept { return *(ArrayT::begin() + length); } + constexpr T * data() noexcept { return ArrayT::data(); } + + constexpr iterator begin() noexcept { return ArrayT::begin();} + constexpr const_iterator cbegin() const noexcept { return ArrayT::cbegin(); } + constexpr iterator end() noexcept { return (ArrayT::begin() + length); } + constexpr const_iterator cend() const noexcept { return (ArrayT::cbegin() + length); } + + constexpr size_type size() const noexcept {return length;} + constexpr size_type max_size() const noexcept {return ArrayT::max_size();} + + constexpr void push_back(const_reference v) noexcept { *(this->begin() + length++) = v; }; + constexpr void push_back(value_type&&v) noexcept { *(this->begin() + length++) = std::move(v); } + + inline void fill(const_reference &v){ ArrayT::fill(v); length = ArrayT::max_size(); } + inline void fill(const_iterator b, const_iterator e) { std::copy(b, e, ArrayT::begin()); length = e - b; } + inline void fill_n(const_iterator b, size_type s) { std::copy(b, b + s, ArrayT::begin()); length = s; } + constexpr void clear() noexcept { this->length = 0; } + +private: + size_type length; +}; + +#endif diff --git a/inc/ringbuffer.h b/inc/ringbuffer.h deleted file mode 100644 index 19639cb..0000000 --- a/inc/ringbuffer.h +++ /dev/null @@ -1,24 +0,0 @@ -#ifndef __INC_RINGBUFFER_H__ -#define __INC_RINGBUFFER_H__ - -#include - -class ringbuffer -{ -public: - ringbuffer(); - - int write(char); - int read(char&); - -private: - enum { - MAX_BUFFER_SIZE = 2 - }; - - std::array buffer; - std::array::iterator head; - std::array::iterator tail; -}; - -#endif diff --git a/src/TarHandler.cc b/src/TarHandler.cc new file mode 100644 index 0000000..30c446c --- /dev/null +++ b/src/TarHandler.cc @@ -0,0 +1,111 @@ +#include +#include +#include "TarHandler.h" + +#define ASCII_TO_NUMBER(num) ((num) - 48) //Converts an ascii digit to the corresponding number + +TarHandler::TarHandler() + : idle(true) + , tar_index(0) + , next_tar_header(0) + , file_size(0) + , read_byte_count(0) + , processed_tar_blocks(0) + , file_processed_bytes(0) +{ +} + +void TarHandler::tcp_in_handler(char* data, std::size_t size) +{ + if(this->idle) { + this->idle = false; + this->tar_index = 0; + this->file_size = 0; + this->next_tar_header; + this->read_byte_count = 0; + this->file_size = 0; + } + + // process incoming buffer + for(std::size_t i = 0; i < size; i++) { + this->tar_block[this->tar_index] = data[i]; + this->read_byte_count++; + if(this->tar_index++ == TAR_BLOCK_SIZE - 1) { + this->tar_block_handler(); + this->tar_index = 0; + } + } +} + +bool TarHandler::tar_block_handler() +{ + this->processed_tar_blocks++; + if(this->next_tar_header == (this->read_byte_count) - TAR_BLOCK_SIZE) { + // Tar header detected + struct tar_file_header tar_header; + memcpy(&tar_header, this->tar_block, TAR_BLOCK_SIZE); + if(!check_checksum(&tar_header)) { + fprintf(stderr, "checksum missmatch\r\n"); + return false; + } + this->file_size = decode_tar_octal(tar_header.file_size, sizeof(tar_header.file_size)); + this->file_processed_bytes = 0; + printf("%s - size: %lu\r\n", tar_header.filename, file_size); + this->next_tar_header = (file_size / TAR_BLOCK_SIZE + 1) * TAR_BLOCK_SIZE + this->processed_tar_blocks * TAR_BLOCK_SIZE; + } else { + std::size_t i = 0; + if((this->file_size - this->file_processed_bytes) >= TAR_BLOCK_SIZE) { + for(i = 0; i < TAR_BLOCK_SIZE; i++) { + printf("%c", this->tar_block[i]); + } + } + else { + for(i = 0; i < (this->file_size - this->file_processed_bytes); i++) { + printf("%c", this->tar_block[i]); + } + } + this->file_processed_bytes += i; + printf("processed bytes: %lu\r\n", this->file_processed_bytes); + } + return true; +} + +uint64_t TarHandler::decode_tar_octal(char* data, std::size_t size) +{ + unsigned char *current_ptr = (unsigned char *) data + size; + uint64_t sum = 0; + uint64_t current_multiplier = 1; + + unsigned char* check_ptr = current_ptr; //This is used to check where the last NUL/space char is + for(; check_ptr >= (unsigned char *) data; --check_ptr) { + if((*check_ptr) == 0 || (*check_ptr) == ' ') { + current_ptr = check_ptr - 1; + } + } + for(; current_ptr >= (unsigned char *) data; --current_ptr) { + sum += ASCII_TO_NUMBER(*current_ptr) * current_multiplier; + current_multiplier *= 8; + } + return sum; +} + +bool TarHandler::check_checksum(struct tar_file_header *tar_header) +{ + char original_checksum[8]; + memcpy(original_checksum, tar_header->checksum, 8); + memset(tar_header->checksum, ' ', 8); + + int64_t unsigned_sum = 0; + int64_t signed_sum = 0; + unsigned char *uc_tar = (unsigned char *)tar_header; + signed char *sc_tar = (signed char *)tar_header; + for(int i = 0; i < TAR_BLOCK_SIZE; i++) { + unsigned_sum += uc_tar[i]; + signed_sum += sc_tar[i]; + } + //Copy back the checksum + memcpy(tar_header->checksum, original_checksum, 8); + //Decode the original checksum + uint64_t reference_checksum = decode_tar_octal(original_checksum, sizeof(original_checksum)); + return (reference_checksum == unsigned_sum || reference_checksum == signed_sum); +} diff --git a/src/TarHandler.h b/src/TarHandler.h new file mode 100644 index 0000000..9f0c7c5 --- /dev/null +++ b/src/TarHandler.h @@ -0,0 +1,53 @@ +#pragma once + +#include + +class TarHandler +{ +public: + struct tar_file_header { + char filename[100]; + char mode[8]; + char uid[8]; + char gid[8]; + char file_size[12]; + char last_modification[12]; + char checksum[8]; + char type_flag; + char linked_file_name[100]; + char ustar_indicator[6]; + char ustar_version[2]; + char owner_user_name[32]; + char owner_group_name[32]; + char device_major_number[8]; + char device_minor_number[8]; + char filename_prefix[155]; + char padding[12]; + }; + +public: + TarHandler(); + + void tcp_in_handler(char* data, std::size_t size); + +private: + uint64_t decode_tar_octal(char* data, std::size_t size); + + bool check_checksum(struct tar_file_header *tar_header); + + bool tar_block_handler(); + + enum { + TAR_BLOCK_SIZE = 512 + }; + + char tar_block[TAR_BLOCK_SIZE]; + std::size_t tar_index; + std::size_t next_tar_header; + std::size_t file_size; + std::size_t read_byte_count; + std::size_t processed_tar_blocks; + std::size_t file_processed_bytes; + + bool idle; +}; diff --git a/src/main.cc b/src/main.cc index d2645ee..b7a2f10 100644 --- a/src/main.cc +++ b/src/main.cc @@ -1,23 +1,38 @@ -#include +#include +#include +#include +#include +#include +#include +#include +#include "TarHandler.h" -#include "ringbuffer.h" -ringbuffer buf; +#define TAR_FILE "test.tar" -int main(void) { - buf.write('a'); - buf.write('b'); - buf.write('c'); +#define BLOCK_SIZE 1522 - char c; - if(buf.read(c)) { - std::cout << c; - } - if(buf.read(c)) { - std::cout << c; - } - if(buf.read(c)) { - std::cout << c; + +int main(void) +{ + int fd = open(TAR_FILE, O_RDONLY); + if(fd < 0) { + fprintf(stderr, "Unable to open %s\r\n", TAR_FILE); + return fd; } + + int res; + char block[BLOCK_SIZE]; + size_t processed_blocks = 0; + TarHandler tar_handler; + do { + res = read(fd, block, sizeof(block)); + tar_handler.tcp_in_handler(block, res); + processed_blocks++; + } while(res > 0); + printf("processed blocks: %lu\r\n", processed_blocks); + + close(fd); + return 0; } diff --git a/src/ringbuffer.cc b/src/ringbuffer.cc deleted file mode 100644 index cc74f64..0000000 --- a/src/ringbuffer.cc +++ /dev/null @@ -1,39 +0,0 @@ -#include "ringbuffer.h" - -ringbuffer::ringbuffer() -{ - head = buffer.begin(); - tail = buffer.begin(); -} - -int ringbuffer::write(char c) -{ - if(head - tail == MAX_BUFFER_SIZE) { - return 0; - } - - if(head == buffer.end()) { - head = buffer.begin(); - } - - *head = c; - head++; - - return 1; -} - -int ringbuffer::read(char& c) -{ - if(head - tail == 0) { - return 0; - } - - if(tail == buffer.end()) { - tail = buffer.begin(); - } - - c = *tail; - tail++; - - return 1; -}