Skip to content

Commit f014c86

Browse files
authored
Fix PAX header writing and handle some errors (#76)
MOPPAND-1661 Signed-off-by: Raul Metsma <[email protected]>
1 parent bd1358d commit f014c86

File tree

2 files changed

+71
-127
lines changed

2 files changed

+71
-127
lines changed

cdoc/Tar.cpp

Lines changed: 61 additions & 115 deletions
Original file line numberDiff line numberDiff line change
@@ -17,22 +17,12 @@
1717
*/
1818

1919
#include "Tar.h"
20+
#include "Utils.h"
2021

2122
#include <array>
22-
#include <sstream>
23+
#include <cstring>
2324

24-
std::vector<std::string>
25-
split (const std::string &s, char delim) {
26-
std::vector<std::string> result;
27-
std::stringstream ss (s);
28-
std::string item;
29-
30-
while (getline (ss, item, delim)) {
31-
result.push_back (item);
32-
}
33-
34-
return result;
35-
}
25+
using namespace libcdoc;
3626

3727
template<std::size_t SIZE>
3828
static int64_t fromOctal(const std::array<char,SIZE> &data)
@@ -59,7 +49,7 @@ static void toOctal(std::array<char,SIZE> &data, int64_t value)
5949
}
6050
}
6151

62-
struct Header {
52+
struct libcdoc::Header {
6353
std::array<char,100> name;
6454
std::array<char, 8> mode;
6555
std::array<char, 8> uid;
@@ -89,9 +79,9 @@ struct Header {
8979
return {unsignedSum, signedSum};
9080
}
9181

92-
bool isNull() {
93-
Header empty = {};
94-
return std::memcmp(this, &empty, sizeof(Header)) == 0;
82+
bool isNull() const {
83+
static const Header empty{};
84+
return *this == empty;
9585
}
9686

9787
bool verify() {
@@ -104,41 +94,14 @@ struct Header {
10494
referenceChecksum == checkSum.second;
10595
}
10696

107-
static const Header Empty;
108-
static const int Size;
97+
bool operator==(const Header&) const = default;
10998
};
11099

111100
static int padding(int64_t size)
112101
{
113102
return sizeof(Header) - size % sizeof(Header);
114103
}
115104

116-
bool
117-
libcdoc::TAR::files(libcdoc::DataSource *src, bool &warning, libcdoc::MultiDataConsumer *dst)
118-
{
119-
TarSource tar(src, false);
120-
std::string name;
121-
int64_t size;
122-
while (tar.next(name, size) == OK) {
123-
dst->open(name, size);
124-
dst->writeAll(tar);
125-
}
126-
warning = !src->isEof();
127-
return true;
128-
}
129-
130-
int64_t writePadding(libcdoc::DataConsumer *dst, uint64_t size) {
131-
std::vector<char> pad(padding(size), 0);
132-
return dst->write((const uint8_t *) pad.data(), pad.size()) == pad.size();
133-
};
134-
135-
int64_t writeHeader (libcdoc::DataConsumer *dst, Header &h, uint64_t size) {
136-
h.chksum.fill(' ');
137-
toOctal(h.size, size);
138-
toOctal(h.chksum, h.checksum().first);
139-
return dst->write((const uint8_t *)&h, sizeof(Header)) == sizeof(Header);
140-
};
141-
142105
std::string toPaxRecord (const std::string &keyword, const std::string &value) {
143106
std::string record = ' ' + keyword + '=' + value + '\n';
144107
std::string result;
@@ -147,51 +110,6 @@ std::string toPaxRecord (const std::string &keyword, const std::string &value) {
147110
return result;
148111
};
149112

150-
bool
151-
libcdoc::TAR::save(libcdoc::DataConsumer& dst, libcdoc::MultiDataSource& src)
152-
{
153-
std::string name;
154-
int64_t size;
155-
while (src.next(name, size)) {
156-
Header h {};
157-
std::string filename(name);
158-
std::string filenameTruncated(filename.begin(), filename.begin() + h.name.size());
159-
std::copy(filenameTruncated.cbegin(), filenameTruncated.cend(), h.name.begin());
160-
161-
// TODO:
162-
// write pax record if name contains special symbols
163-
if(filename.size() > 100 || size > 07777777) {
164-
h.typeflag = 'x';
165-
std::string paxData;
166-
if(filename.size() > 100)
167-
paxData += toPaxRecord("path", filename);
168-
if(size > 07777777)
169-
paxData += toPaxRecord("size", std::to_string(size));
170-
if(!writeHeader(&dst, h, paxData.size()) ||
171-
dst.write((const uint8_t *) paxData.data(), paxData.size()) != paxData.size() ||
172-
!writePadding(&dst, paxData.size()))
173-
return false;
174-
}
175-
176-
h.typeflag = '0';
177-
if(!writeHeader(&dst, h, size))
178-
return false;
179-
size_t total_written = 0;
180-
while (!src.isEof()) {
181-
uint8_t buf[256];
182-
auto n_read = src.read(buf, 256);
183-
if (n_read < 0) return false;
184-
dst.write(buf, n_read);
185-
total_written += n_read;
186-
}
187-
writePadding(&dst, total_written);
188-
189-
}
190-
Header empty = {};
191-
return dst.write((const uint8_t *)&empty, sizeof(Header)) == sizeof(Header) &&
192-
dst.write((const uint8_t *)&empty, sizeof(Header)) == sizeof(Header);
193-
}
194-
195113
libcdoc::TarConsumer::TarConsumer(DataConsumer *dst, bool take_ownership)
196114
: _dst(dst), _owned(take_ownership)
197115
{
@@ -211,17 +129,44 @@ libcdoc::TarConsumer::write(const uint8_t *src, size_t size)
211129
return _dst->write(src, size);
212130
}
213131

132+
libcdoc::result_t
133+
libcdoc::TarConsumer::writeHeader(const Header &h) {
134+
if(auto rv = _dst->write((const uint8_t *)&h, sizeof(Header)); rv != sizeof(Header))
135+
return rv < OK ? rv : OUTPUT_ERROR;
136+
return OK;
137+
}
138+
139+
libcdoc::result_t
140+
libcdoc::TarConsumer::writeHeader(Header &h, int64_t size) {
141+
h.chksum.fill(' ');
142+
toOctal(h.size, size);
143+
toOctal(h.chksum, h.checksum().first);
144+
return writeHeader(h);
145+
}
146+
147+
libcdoc::result_t
148+
libcdoc::TarConsumer::writePadding(int64_t size) {
149+
std::array<uint8_t,sizeof(libcdoc::Header)> pad {};
150+
auto padSize = padding(size);
151+
if(auto rv = _dst->write(pad.data(), padSize); rv != padSize)
152+
return rv < OK ? rv : OUTPUT_ERROR;
153+
return OK;
154+
}
155+
214156
libcdoc::result_t
215157
libcdoc::TarConsumer::close()
216158
{
217-
if (_current_size) {
218-
writePadding(_dst, _current_size);
219-
}
220-
Header empty = {};
221-
_dst->write((const uint8_t *)&empty, sizeof(Header));
222-
_dst->write((const uint8_t *)&empty, sizeof(Header));
159+
if (_current_size > 0) {
160+
if(auto rv = writePadding(_current_size); rv != OK)
161+
return rv;
162+
}
163+
Header empty = {};
164+
if(auto rv = writeHeader(empty); rv != OK)
165+
return rv;
166+
if(auto rv = writeHeader(empty); rv != OK)
167+
return rv;
223168
if (_owned) {
224-
_dst->close();
169+
return _dst->close();
225170
}
226171
return OK;
227172
}
@@ -235,32 +180,33 @@ libcdoc::TarConsumer::isError()
235180
libcdoc::result_t
236181
libcdoc::TarConsumer::open(const std::string& name, int64_t size)
237182
{
238-
if (_current_size) {
239-
writePadding(_dst, _current_size);
240-
}
241-
_current_size = size;
183+
if (_current_size > 0) {
184+
if(auto rv = writePadding(_current_size); rv != OK)
185+
return rv;
186+
}
187+
188+
_current_size = size;
242189
Header h {};
243-
std::string filename(name);
244-
size_t len = name.size();
245-
if (len > h.name.size()) len = h.name.size();
246-
std::copy(name.cbegin(), name.cbegin() + len, h.name.begin());
190+
size_t len = std::min(name.size(), h.name.size());
191+
std::copy_n(name.cbegin(), len, h.name.begin());
247192

248193
// TODO: Create pax record if name contains special symbols
249-
if(filename.size() > 100 || size > 07777777) {
194+
if(name.size() > 100 || size > 07777777) {
250195
h.typeflag = 'x';
251196
std::string paxData;
252-
if(filename.size() > 100)
253-
paxData += toPaxRecord("path", filename);
197+
if(name.size() > 100)
198+
paxData += toPaxRecord("path", name);
254199
if(size > 07777777)
255200
paxData += toPaxRecord("size", std::to_string(size));
256-
return writeHeader(_dst, h, paxData.size()) &&
257-
_dst->write((const uint8_t *) paxData.data(), paxData.size()) == paxData.size() &&
258-
writePadding(_dst, paxData.size()) ? OK : OUTPUT_ERROR;
259-
}
260-
201+
if (auto rv = writeHeader(h, paxData.size()); rv != OK)
202+
return rv;
203+
if (auto rv = _dst->write((const uint8_t *) paxData.data(), paxData.size()); rv != paxData.size())
204+
return rv < OK ? rv : OUTPUT_ERROR;
205+
if (auto rv = writePadding(paxData.size()); rv != OK)
206+
return rv;
207+
}
261208
h.typeflag = '0';
262-
if(writeHeader(_dst, h, size) < 0) return OUTPUT_ERROR;
263-
return OK;
209+
return writeHeader(h, size);
264210
}
265211

266212
libcdoc::TarSource::TarSource(DataSource *src, bool take_ownership)

cdoc/Tar.h

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -21,27 +21,25 @@
2121

2222
#include <cdoc/Io.h>
2323

24-
#include <cstring>
2524
namespace libcdoc {
2625

27-
struct TAR {
28-
explicit TAR() = default;
26+
struct Header;
2927

30-
static bool files(libcdoc::DataSource *src, bool &warning, libcdoc::MultiDataConsumer *dst);
31-
static bool save(libcdoc::DataConsumer& dst, libcdoc::MultiDataSource& src);
32-
};
33-
34-
struct TarConsumer : public MultiDataConsumer
28+
struct TarConsumer final : public MultiDataConsumer
3529
{
3630
public:
3731
TarConsumer(DataConsumer *dst, bool take_ownership);
3832
~TarConsumer();
3933

40-
libcdoc::result_t write(const uint8_t *src, size_t size) override final;
41-
libcdoc::result_t close() override final;
42-
bool isError() override final;
43-
libcdoc::result_t open(const std::string& name, int64_t size) override final;
34+
libcdoc::result_t write(const uint8_t *src, size_t size) final;
35+
libcdoc::result_t close() final;
36+
bool isError() final;
37+
libcdoc::result_t open(const std::string& name, int64_t size) final;
4438
private:
39+
result_t writeHeader(const Header &h);
40+
result_t writeHeader(Header &h, int64_t size);
41+
result_t writePadding(int64_t size);
42+
4543
DataConsumer *_dst;
4644
bool _owned;
4745
int64_t _current_size = 0;

0 commit comments

Comments
 (0)