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
3727template <std::size_t SIZE>
3828static 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
111100static 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-
142105std::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-
195113libcdoc::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+
214156libcdoc::result_t
215157libcdoc::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()
235180libcdoc::result_t
236181libcdoc::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
266212libcdoc::TarSource::TarSource (DataSource *src, bool take_ownership)
0 commit comments