Tar handler
This commit is contained in:
parent
828d55e708
commit
6bd3ff85a5
16
.vscode/settings.json
vendored
Normal file
16
.vscode/settings.json
vendored
Normal file
@ -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"
|
||||
}
|
||||
}
|
2
Makefile
2
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
|
||||
|
43
inc/Buffer.h
Normal file
43
inc/Buffer.h
Normal file
@ -0,0 +1,43 @@
|
||||
#ifndef __INC_BUFFER_H__
|
||||
#define __INC_BUFFER_H__
|
||||
|
||||
template<typename T, std::size_t S>
|
||||
class Buffer
|
||||
: std::array<T, S>
|
||||
{
|
||||
typedef std::array<T,S> 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
|
@ -1,24 +0,0 @@
|
||||
#ifndef __INC_RINGBUFFER_H__
|
||||
#define __INC_RINGBUFFER_H__
|
||||
|
||||
#include <array>
|
||||
|
||||
class ringbuffer
|
||||
{
|
||||
public:
|
||||
ringbuffer();
|
||||
|
||||
int write(char);
|
||||
int read(char&);
|
||||
|
||||
private:
|
||||
enum {
|
||||
MAX_BUFFER_SIZE = 2
|
||||
};
|
||||
|
||||
std::array<char, MAX_BUFFER_SIZE> buffer;
|
||||
std::array<char, MAX_BUFFER_SIZE>::iterator head;
|
||||
std::array<char, MAX_BUFFER_SIZE>::iterator tail;
|
||||
};
|
||||
|
||||
#endif
|
111
src/TarHandler.cc
Normal file
111
src/TarHandler.cc
Normal file
@ -0,0 +1,111 @@
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
#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);
|
||||
}
|
53
src/TarHandler.h
Normal file
53
src/TarHandler.h
Normal file
@ -0,0 +1,53 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
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;
|
||||
};
|
47
src/main.cc
47
src/main.cc
@ -1,23 +1,38 @@
|
||||
#include <iostream>
|
||||
#include <stdio.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
Loading…
Reference in New Issue
Block a user