-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathtarstream.hh
195 lines (141 loc) · 3.87 KB
/
tarstream.hh
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
#ifndef TARSTREAM_HH
#define TARSTREAM_HH
#include <cstdint>
#include <filesystem>
#include <fstream>
#include <iostream>
#include <list>
#include <memory>
#include <type_traits>
#include <unordered_map>
#include <vector>
namespace TAR
{
enum class Status
{
OK,
END,
ERROR
};
namespace fs = std::filesystem;
typedef std::vector<std::uint8_t> Data;
constexpr std::uint32_t BLOCK_SIZE = 512;
// The header block(POSIX 1003.1-1990)
struct Header
{
char name[100];
char mode[8];
char uid[8];
char gid[8];
char size[12];
char mtime[12];
char chksum[8];
char typeflag;
char linkname[100];
char magic[6];
char version[2];
char uname[32];
char gname[32];
char devmajor[8];
char devminor[8];
char prefix[155];
std::uint32_t size_in_blocks() const;
std::uint32_t size_in_bytes() const;
friend std::ostream& operator<<(std::ostream& os, const Header& header);
};
struct Block
{
union
{
std::uint8_t as_data[BLOCK_SIZE];
Header as_header;
};
std::uint32_t calculate_checksum() const;
bool is_zero_block() const;
friend std::ostream& operator<<(std::ostream& os, const Block& block);
};
struct File
{
Header header;
std::string name;
private:
std::uint32_t m_block_id;
std::uint32_t m_record_id;
friend class Parser;
};
class BlockStream
{
public:
BlockStream(const std::string& file_path, std::uint32_t blocking_factor = 20);
virtual ~BlockStream() = default;
BlockStream(const BlockStream& other) = delete;
BlockStream& operator=(const BlockStream& other) = delete;
std::uint32_t record_id();
std::uint32_t block_id();
protected:
fs::path m_file_path;
std::uint32_t m_blocking_factor;
std::uint32_t m_block_id;
std::uint32_t m_record_id;
std::unique_ptr<Block[]> m_record;
std::fstream m_stream;
};
class InStream : public BlockStream
{
public:
InStream(fs::path file_path, std::uint32_t blocking_factor = 20);
~InStream() = default;
InStream(const InStream& other) = delete;
InStream& operator=(const InStream& other) = delete;
Status read_block(Block& raw, bool advance = true);
Status seek_record(std::uint32_t record_id);
Status skip_blocks(std::uint32_t count);
private:
Status read_record();
std::uint32_t m_records_in_file;
bool m_should_read;
};
class Parser
{
public:
Parser(InStream& tar_stream);
~Parser() = default;
Parser(const Parser& other) = delete;
Parser& operator=(const Parser& other) = delete;
Status next_file(File& file);
Data read_file(File& file);
Status list_files(std::list<File>& list);
private:
Status check_block(Block& block);
Data unpack(const Header& header);
InStream& m_stream;
};
class OutStream : public BlockStream
{
public:
OutStream(const std::string& file_path, std::uint32_t blocking_factor = 20);
~OutStream();
OutStream(const OutStream& other) = delete;
OutStream& operator=(const OutStream& other) = delete;
Status write_block(const Block& block);
Status write_blocks(const std::vector<Block>& blocks);
private:
Status flush_record();
};
class Archiver
{
public:
Archiver() = default;
~Archiver() = default;
Archiver(const Archiver& other) = delete;
Archiver& operator=(const Archiver& other) = delete;
Status archive(const fs::path& src, const fs::path& dest, std::uint32_t blocking_factor = 20);
private:
Status create_header(const fs::path& path, Block& header_block);
void create_long_name_blocks(const std::string& path,
std::vector<Block>& blocks,
const Header& real_header);
Status pack(const fs::path& path, std::vector<Block>& blocks);
};
}
#endif // TARSTREAM_HH