Skip to content

Commit 3cf21b0

Browse files
committed
Fix PAX header writing and handle some errors
MOPPAND-1661 Signed-off-by: Raul Metsma <[email protected]>
1 parent bd1358d commit 3cf21b0

File tree

2 files changed

+67
-125
lines changed

2 files changed

+67
-125
lines changed

cdoc/Tar.cpp

Lines changed: 57 additions & 113 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;
@@ -103,42 +93,13 @@ struct Header {
10393
return referenceChecksum == checkSum.first ||
10494
referenceChecksum == checkSum.second;
10595
}
106-
107-
static const Header Empty;
108-
static const int Size;
10996
};
11097

11198
static int padding(int64_t size)
11299
{
113100
return sizeof(Header) - size % sizeof(Header);
114101
}
115102

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-
142103
std::string toPaxRecord (const std::string &keyword, const std::string &value) {
143104
std::string record = ' ' + keyword + '=' + value + '\n';
144105
std::string result;
@@ -147,51 +108,6 @@ std::string toPaxRecord (const std::string &keyword, const std::string &value) {
147108
return result;
148109
};
149110

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-
195111
libcdoc::TarConsumer::TarConsumer(DataConsumer *dst, bool take_ownership)
196112
: _dst(dst), _owned(take_ownership)
197113
{
@@ -211,17 +127,44 @@ libcdoc::TarConsumer::write(const uint8_t *src, size_t size)
211127
return _dst->write(src, size);
212128
}
213129

130+
libcdoc::result_t
131+
libcdoc::TarConsumer::writeHeader(const Header &h) {
132+
if(auto rv = _dst->write((const uint8_t *)&h, sizeof(Header)); rv != sizeof(Header))
133+
return rv < OK ? rv : OUTPUT_ERROR;
134+
return OK;
135+
}
136+
137+
libcdoc::result_t
138+
libcdoc::TarConsumer::writeHeader(Header &h, int64_t size) {
139+
h.chksum.fill(' ');
140+
toOctal(h.size, size);
141+
toOctal(h.chksum, h.checksum().first);
142+
return writeHeader(h);
143+
}
144+
145+
libcdoc::result_t
146+
libcdoc::TarConsumer::writePadding(int64_t size) {
147+
std::array<uint8_t,sizeof(libcdoc::Header)> pad {};
148+
auto padSize = padding(size);
149+
if(auto rv = _dst->write(pad.data(), padSize); rv != padSize)
150+
return rv < OK ? rv : OUTPUT_ERROR;
151+
return OK;
152+
}
153+
214154
libcdoc::result_t
215155
libcdoc::TarConsumer::close()
216156
{
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));
157+
if (_current_size > 0) {
158+
if(auto rv = writePadding(_current_size); rv != OK)
159+
return rv;
160+
}
161+
Header empty = {};
162+
if(auto rv = writeHeader(empty); rv != OK)
163+
return rv;
164+
if(auto rv = writeHeader(empty); rv != OK)
165+
return rv;
223166
if (_owned) {
224-
_dst->close();
167+
return _dst->close();
225168
}
226169
return OK;
227170
}
@@ -235,32 +178,33 @@ libcdoc::TarConsumer::isError()
235178
libcdoc::result_t
236179
libcdoc::TarConsumer::open(const std::string& name, int64_t size)
237180
{
238-
if (_current_size) {
239-
writePadding(_dst, _current_size);
240-
}
241-
_current_size = size;
181+
if (_current_size > 0) {
182+
if(auto rv = writePadding(_current_size); rv != OK)
183+
return rv;
184+
}
185+
186+
_current_size = size;
242187
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());
188+
size_t len = std::min(name.size(), h.name.size());
189+
std::copy_n(name.cbegin(), len, h.name.begin());
247190

248191
// TODO: Create pax record if name contains special symbols
249-
if(filename.size() > 100 || size > 07777777) {
192+
if(name.size() > 100 || size > 07777777) {
250193
h.typeflag = 'x';
251194
std::string paxData;
252-
if(filename.size() > 100)
253-
paxData += toPaxRecord("path", filename);
195+
if(name.size() > 100)
196+
paxData += toPaxRecord("path", name);
254197
if(size > 07777777)
255198
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-
199+
if (auto rv = writeHeader(h, paxData.size()); rv != OK)
200+
return rv;
201+
if (auto rv = _dst->write((const uint8_t *) paxData.data(), paxData.size()); rv != paxData.size())
202+
return rv < OK ? rv : OUTPUT_ERROR;
203+
if (auto rv = writePadding(paxData.size()); rv != OK)
204+
return rv;
205+
}
261206
h.typeflag = '0';
262-
if(writeHeader(_dst, h, size) < 0) return OUTPUT_ERROR;
263-
return OK;
207+
return writeHeader(h, size);
264208
}
265209

266210
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)