1
2 #include "filereader.h"
3
4 #include <unistd.h>
5 #include "fileio.h"
6 #include <fcntl.h>
7 #include <sys/mman.h>
8 #include <errno.h>
9 #include <limits>
10 #include <signal.h>
11
12 #include "csmapping.h"
13 #include "aclogger.h"
14 #include "filelocks.h"
15 #include "lockable.h"
16 #include "debug.h"
17
18 #include <iostream>
19 #include <atomic>
20
21 #ifdef HAVE_SSL
22 #include <openssl/sha.h>
23 #include <openssl/md5.h>
24 #elif defined(HAVE_TOMCRYPT)
25 #include <tomcrypt.h>
26 #endif
27
28 #ifdef DEBUG
29 //#define SHRINKTEST
30 #endif
31
32 // must be something sensible, ratio impacts stack size by inverse power of 2
33 #define BUFSIZEMIN 4095 // makes one page on i386 and should be enough for typical index files
34 #define BUFSIZEMAX 16*4096
35
36
37 #ifdef MINIBUILD
38 #undef HAVE_LIBBZ2
39 #undef HAVE_ZLIB
40 #undef HAVE_LZMA
41 #endif
42
43 using namespace std;
44
45 namespace acng
46 {
47 // to make sure not to deal with incomplete operations from a signal handler
48 class tMmapEntry
49 {
50 public:
51 std::atomic_bool valid;
52 pthread_t threadref;
53 string path;
tMmapEntry()54 tMmapEntry() : threadref() {
55 valid.store(false);
56 }
57 };
58
59 #ifdef SIGBUSHUNTING
60 // this weird kludge is only needed in order to access this data from POSIX signal handlers
61 // which needs to be both, reliable and lock-free
62 tMmapEntry g_mmapMemory[10];
63 lockable g_mmapMemoryLock;
64 #endif
65
66 class IDecompressor
67 {
68 public:
69 bool eof=false;
70 mstring *psError = nullptr;
~IDecompressor()71 virtual ~IDecompressor() {};
72 virtual bool UncompMore(char *szInBuf, size_t nBufSize, size_t &nBufPos, acbuf &UncompBuf) =0;
73 virtual bool Init() =0;
74 };
75
76 #ifdef HAVE_LIBBZ2
77 #include <bzlib.h>
78 class tBzDec : public IDecompressor
79 {
80 bz_stream strm = bz_stream();
81 public:
Init()82 bool Init() override
83 {
84 if (BZ_OK == BZ2_bzDecompressInit(&strm, 1, EXTREME_MEMORY_SAVING))
85 return true;
86 // crap, no proper sanity checks in BZ2_bzerror
87 if(psError)
88 psError->assign("BZIP2 initialization error");
89 return false;
90
91 }
~tBzDec()92 ~tBzDec()
93 {
94 BZ2_bzDecompressEnd(&strm);
95 }
UncompMore(char * szInBuf,size_t nBufSize,size_t & nBufPos,acbuf & UncompBuf)96 virtual bool UncompMore(char *szInBuf, size_t nBufSize, size_t &nBufPos, acbuf &UncompBuf) override
97 {
98 strm.next_in = szInBuf + nBufPos;
99 strm.avail_in = nBufSize - nBufPos;
100 strm.next_out = UncompBuf.wptr();
101 strm.avail_out = UncompBuf.freecapa();
102
103 int ret = BZ2_bzDecompress(&strm);
104 if (ret == BZ_STREAM_END || ret == BZ_OK)
105 {
106 nBufPos = nBufSize - strm.avail_in;
107 unsigned nGotBytes = UncompBuf.freecapa() - strm.avail_out;
108 UncompBuf.got(nGotBytes);
109 eof = ret == BZ_STREAM_END;
110 return true;
111 }
112 // or corrupted data?
113 eof = true;
114 // eeeeks bz2, no robust error getter, no prepared error message :-(
115 if(psError)
116 *psError = mstring("BZIP2 error ")+ltos(ret);
117 return false;
118 }
119 };
120 static const uint8_t bz2Magic[] =
121 { 'B', 'Z', 'h' };
122 #endif
123
124 #ifdef HAVE_ZLIB
125 #include <zlib.h>
126 class tGzDec : public IDecompressor
127 {
128 z_stream strm = z_stream();
129 public:
Init()130 bool Init() override
131 {
132 if (Z_OK == inflateInit2(&strm, 47))
133 return true;
134 if (psError)
135 psError->assign("ZLIB initialization error");
136 return false;
137 }
~tGzDec()138 ~tGzDec()
139 {
140 deflateEnd(&strm);
141 }
UncompMore(char * szInBuf,size_t nBufSize,size_t & nBufPos,acbuf & UncompBuf)142 virtual bool UncompMore(char *szInBuf, size_t nBufSize, size_t &nBufPos, acbuf &UncompBuf) override
143 {
144 strm.next_in = (uint8_t*) szInBuf + nBufPos;
145 strm.avail_in = nBufSize - nBufPos;
146 strm.next_out = (uint8_t*) UncompBuf.wptr();
147 strm.avail_out = UncompBuf.freecapa();
148
149 int ret = inflate(&strm, Z_NO_FLUSH);
150 if (ret == Z_STREAM_END || ret == Z_OK)
151 {
152 nBufPos = nBufSize - strm.avail_in;
153 unsigned nGotBytes = UncompBuf.freecapa() - strm.avail_out;
154 UncompBuf.got(nGotBytes);
155 eof = ret == Z_STREAM_END;
156 return true;
157 }
158 // or corrupted data?
159 eof = true;
160 if(psError)
161 *psError = mstring("ZLIB error: ") + (strm.msg ? mstring(strm.msg) : ltos(ret));
162 return false;
163 }
164 };
165 static const uint8_t gzMagic[] =
166 { 0x1f, 0x8b, 0x8 };
167 #endif
168
169 #ifdef HAVE_LZMA
170 #include <lzma.h>
171
172 class tXzDec : public IDecompressor
173 {
174 lzma_stream strm = lzma_stream();
175 bool lzmaFormat;
176 public:
tXzDec(bool bLzma)177 tXzDec(bool bLzma) : lzmaFormat(bLzma) {};
178
Init()179 bool Init() override
180 {
181 auto x = (lzmaFormat ? lzma_alone_decoder(&strm,
182 EXTREME_MEMORY_SAVING ? 32000000 : MAX_VAL(uint64_t))
183 : lzma_stream_decoder(&strm,
184 EXTREME_MEMORY_SAVING ? 32000000 : MAX_VAL(uint64_t),
185 LZMA_TELL_UNSUPPORTED_CHECK | LZMA_CONCATENATED));
186 if(LZMA_OK == x)
187 return true;
188 if(psError)
189 psError->assign("LZMA initialization error");
190 return false;
191 }
~tXzDec()192 ~tXzDec()
193 {
194 lzma_end(&strm);
195 }
UncompMore(char * szInBuf,size_t nBufSize,size_t & nBufPos,acbuf & UncompBuf)196 virtual bool UncompMore(char *szInBuf, size_t nBufSize, size_t &nBufPos, acbuf &UncompBuf) override
197 {
198 strm.next_in = (uint8_t*) szInBuf + nBufPos;
199 strm.avail_in = nBufSize - nBufPos;
200 strm.next_out = (uint8_t*) UncompBuf.wptr();
201 strm.avail_out = UncompBuf.freecapa();
202
203 lzma_ret ret=lzma_code(&strm, strm.avail_in ? LZMA_RUN : LZMA_FINISH);
204 if (ret == LZMA_STREAM_END || ret == LZMA_OK)
205 {
206 nBufPos = nBufSize - strm.avail_in;
207 unsigned nGotBytes = UncompBuf.freecapa() - strm.avail_out;
208 UncompBuf.got(nGotBytes);
209 eof = ret == LZMA_STREAM_END;
210 return true;
211 }
212 // or corrupted data?
213 eof = true;
214 if(psError)
215 *psError = mstring("LZMA error ")+ltos(ret);
216 return false;
217 }
218 };
219 static const uint8_t xzMagic[] =
220 { 0xfd, '7', 'z', 'X', 'Z', 0x0 },
221 lzmaMagic[] = {0x5d, 0, 0, 0x80};
222 #endif
223
filereader()224 filereader::filereader()
225 :
226 m_bError(false),
227 m_bEof(false),
228 m_szFileBuf((char*)MAP_FAILED),
229 m_nBufSize(0),
230 m_nBufPos(0),
231 m_nCurLine(0),
232 m_fd(-1),
233 m_nEofLines(0)
234 {
235 };
236
OpenFile(const string & sFilename,bool bNoMagic,unsigned nFakeTrailingNewlines)237 bool filereader::OpenFile(const string & sFilename, bool bNoMagic, unsigned nFakeTrailingNewlines)
238 {
239 Close(); // reset to clean state
240 m_nEofLines=nFakeTrailingNewlines;
241
242 m_fd = open(sFilename.c_str(), O_RDONLY);
243 #ifdef SHRINKTEST
244 m_fd = open(sFilename.c_str(), O_RDWR);
245 #warning destruction mode!!!
246 #endif
247
248 if (m_fd < 0)
249 {
250 m_sErrorString=tErrnoFmter();
251 return false;
252 }
253
254 if (bNoMagic)
255 m_Dec.reset();
256 #ifdef HAVE_LIBBZ2
257 else if (endsWithSzAr(sFilename, ".bz2"))
258 m_Dec.reset(new tBzDec);
259 #endif
260 #ifdef HAVE_ZLIB
261 else if (endsWithSzAr(sFilename, ".gz"))
262 m_Dec.reset(new tGzDec);
263 #endif
264 #ifdef HAVE_LZMA
265 else if(endsWithSzAr(sFilename, ".xz"))
266 m_Dec.reset(new tXzDec(false));
267 else if (endsWithSzAr(sFilename, ".lzma"))
268 m_Dec.reset(new tXzDec(true));
269 #endif
270 else // unknown... ok, probe it
271 {
272 m_UncompBuf.setsize(10);
273 if(m_UncompBuf.sysread(m_fd) >= 10)
274 {
275 if(false) {}
276 #ifdef HAVE_ZLIB
277 else if (0 == memcmp(gzMagic, m_UncompBuf.rptr(), _countof(gzMagic)))
278 m_Dec.reset(new tGzDec);
279 #endif
280 #ifdef HAVE_LIBBZ2
281 else if (0 == memcmp(bz2Magic, m_UncompBuf.rptr(), _countof(bz2Magic)))
282 m_Dec.reset(new tBzDec);
283 #endif
284 #ifdef HAVE_LZMA
285 else if (0 == memcmp(xzMagic, m_UncompBuf.rptr(), _countof(xzMagic)))
286 m_Dec.reset(new tXzDec(false));
287 else if (0 == memcmp(lzmaMagic, m_UncompBuf.rptr(), _countof(lzmaMagic)))
288 m_Dec.reset(new tXzDec(true));
289 #endif
290 }
291 }
292
293 if (m_Dec.get())
294 {
295 m_Dec->psError = &m_sErrorString;
296 if(!m_Dec->Init())
297 return false;
298 m_UncompBuf.clear();
299 m_UncompBuf.setsize(BUFSIZEMIN);
300 }
301
302 tErrnoFmter fmt;
303
304 struct stat statbuf;
305 if(0!=fstat(m_fd, &statbuf))
306 {
307 m_sErrorString=tErrnoFmter();
308 return false;
309 }
310
311 // this makes sure not to truncate file while it's mmaped
312 m_mmapLock = TFileShrinkGuard::Acquire(statbuf);
313
314 // LFS on 32bit? That's not good for mmap. Don't risk incorrect behaviour.
315 if(uint64_t(statbuf.st_size) > MAX_VAL(size_t))
316 {
317 errno=EFBIG;
318 m_sErrorString=tErrnoFmter();
319 return false;
320 }
321
322 if(statbuf.st_size>0)
323 {
324 m_szFileBuf = (char*) mmap(0, statbuf.st_size, PROT_READ, MAP_SHARED, m_fd, 0);
325 if(m_szFileBuf==MAP_FAILED)
326 {
327 m_sErrorString=tErrnoFmter();
328 return false;
329 }
330 m_nBufSize = statbuf.st_size;
331 }
332 else if(m_Dec.get())
333 {
334 // compressed file but empty -> error
335 m_sErrorString="Truncated compressed file";
336 return false;
337 }
338 else
339 {
340 m_szFileBuf = nullptr;
341 m_nBufSize = 0;
342 }
343
344 // ORDER DOES MATTER! No returns anymore before the mmap entry was booked in "the memory"
345
346 #ifdef HAVE_MADVISE
347 // if possible, prepare to read that
348 posix_madvise(m_szFileBuf, statbuf.st_size, POSIX_MADV_SEQUENTIAL);
349 #endif
350
351 #ifdef SHRINKTEST
352 if (ftruncate(m_fd, GetSize()/2) < 0)
353 {
354 perror ("ftruncate");
355 ::exit(1);
356 }
357 #endif
358
359 m_nBufPos=0;
360 m_nCurLine=0;
361 m_bError = m_bEof = false;
362
363 #ifdef SIGBUSHUNTING
364 {
365 // try to keep a thread reference in some free slot
366 lockguard g(g_mmapMemoryLock);
367 for(auto &x : g_mmapMemory)
368 {
369 if(!x.valid.load())
370 {
371 x.path=sFilename;
372 x.threadref=pthread_self();
373 x.valid.store(true);
374 }
375 }
376 }
377 #endif
378 return true;
379 }
380
CheckGoodState(bool bErrorsConsiderFatal,cmstring * reportFilePath) const381 bool filereader::CheckGoodState(bool bErrorsConsiderFatal, cmstring *reportFilePath) const
382 {
383 if (!m_bError)
384 return true;
385 if (!bErrorsConsiderFatal)
386 return false;
387 cerr << "Error opening file";
388 if (reportFilePath)
389 cerr << " " << *reportFilePath;
390 cerr << " (" << m_sErrorString << "), terminating." << endl;
391 exit(EXIT_FAILURE);
392
393 }
394
Close()395 void filereader::Close()
396 {
397 m_nCurLine=0;
398 m_mmapLock.reset();
399
400 if (m_szFileBuf != MAP_FAILED)
401 {
402 #ifdef SIGBUSHUNTING
403 {
404 lockguard g(g_mmapMemoryLock);
405 for (auto &x : g_mmapMemory)
406 {
407 if (x.valid.load()
408 && pthread_equal(pthread_self(), x.threadref)
409 && m_mmapLock.get() && x.path == m_mmapLock->path)
410 x.valid = false;
411 }
412 }
413 #endif
414
415 munmap(m_szFileBuf, m_nBufSize);
416 m_szFileBuf = (char*) MAP_FAILED;
417 }
418
419 checkforceclose(m_fd);
420 m_mmapLock.reset();
421 m_Dec.reset();
422
423 m_nBufSize=0;
424
425 m_bError = m_bEof = true; // will be cleared in Open()
426 m_sErrorString=cmstring("Not initialized");
427 }
428
~filereader()429 filereader::~filereader() {
430 Close();
431 }
432
433 std::atomic_int g_nThreadsToKill;
434
handle_sigbus()435 void handle_sigbus()
436 {
437 if (!cfg::sigbuscmd.empty())
438 {
439 /*static char buf[21];
440 sprintf(buf, "%u", (unsigned) getpid());
441 setenv("ACNGPID", buf, 1);
442 */
443 acng::ignore_value(system(cfg::sigbuscmd.c_str()));
444 }
445 else
446 {
447
448 log::err(
449 "FATAL ERROR: apparently an IO error occurred, while reading files. "
450 "Please check your system logs for related errors reports. Also consider "
451 "using the BusAction option, see Apt-Cacher NG Manual for details");
452 }
453 #if 1
454
455 #ifdef SIGBUSHUNTING
456 for (auto &x : g_mmapMemory)
457 {
458 if (!x.valid.load())
459 continue;
460 log::err(string("FATAL ERROR: probably IO error occurred, probably while reading the file ")
461 +x.path+" . Please check your system logs for related errors.");
462 }
463 #endif
464
465 #else
466 // attempt to pass the signal around threads, stopping the one troublemaker
467 std::cerr << "BUS ARRIVED" << std::endl;
468
469 bool metoo = false;
470
471 if (g_nThreadsToKill.load())
472 goto suicid;
473
474 g_degraded.store(true);
475
476 // this must run lock-free
477 for (auto &x : g_mmapMemory)
478 {
479 if (!x.valid.load())
480 continue;
481 log::err(
482 string("FATAL ERROR: probably IO error occurred, probably while reading the file ")
483 + x.path + " . Please check your system logs for related errors.");
484
485 if (pthread_equal(pthread_self(), x.threadref))
486 metoo = true;
487 else
488 {
489 g_nThreadsToKill.fetch_add(1);
490 pthread_kill(x.threadref, SIGBUS);
491 }
492 }
493
494 if (!metoo)
495 return;
496
497 suicid: log::err("FATAL ERROR: SIGBUS, probably caused by an IO error. "
498 "Please check your system logs for related errors.");
499
500 g_nThreadsToKill.fetch_add(-1);
501 pthread_exit(0);
502 #endif
503 }
504
GetOneLine(string & sOut,bool bForceUncompress)505 bool filereader::GetOneLine(string & sOut, bool bForceUncompress) {
506
507 sOut.clear();
508
509 if(m_bEof && m_nEofLines-- >0)
510 return true; // just the empty line
511
512 // stop flags set in previous run
513 if(m_bError || m_bEof)
514 return false;
515
516 const char *rbuf;
517 size_t nRest;
518
519 // navigate to the place where the reading starts
520
521 // needing an uncompression step? Either in the beginning or when doing the subcall
522 if(m_Dec.get())
523 {
524 if ((!m_nBufPos || bForceUncompress) && !m_Dec->eof)
525 {
526 m_UncompBuf.move(); // make free as much as possible
527
528 // must uncompress but the buffer is full. Resize it, if not possible, fail only then.
529 if(bForceUncompress && 0==m_UncompBuf.freecapa())
530 {
531 if (m_UncompBuf.totalcapa() >= BUFSIZEMAX
532 || !m_UncompBuf.setsize(m_UncompBuf.totalcapa() * 2))
533 {
534 m_bError = true;
535 m_sErrorString=mstring("Failed to allocate decompression buffer memory");
536 return false;
537 }
538 }
539
540 m_bError = ! m_Dec->UncompMore(m_szFileBuf, m_nBufSize, m_nBufPos, m_UncompBuf);
541 }
542
543 nRest=m_UncompBuf.size();
544 rbuf=m_UncompBuf.rptr();
545 }
546 else
547 {
548 if(m_nBufPos>=m_nBufSize)
549 m_bEof=true;
550 // detect eof and remember that, for now or later calls
551 nRest = m_bEof ? 0 : m_nBufSize-m_nBufPos;
552 rbuf=m_szFileBuf+m_nBufPos;
553 }
554
555 // look for end in the rest of buffer (may even be nullsized then it fails implicitely, newline decides),
556 // on miss -> try to get more, check whether the available size changed,
557 // on success -> retry
558
559 //const char *newline=mempbrk(rbuf, "\r\n", nRest);
560 //const char *crptr=(const char*) memchr(rbuf, '\r', nRest);
561 //const char *lfptr=(const char*) memchr(rbuf, '\n', nRest);
562 //const char *newline = (crptr&&lfptr) ? std::min(crptr,lfptr) : std::max(crptr,lfptr);
563 const char *newline=0;
564 for(const char *x=rbuf; x<rbuf+nRest; ++x)
565 {
566 if('\r' == *x || '\n' == *x) // that's what compilers like most :-(
567 {
568 newline=x;
569 break;
570 }
571 }
572
573 tStrPos nLineLen, nDropLen;
574
575 if(newline)
576 {
577 nLineLen=newline-rbuf;
578 nDropLen=nLineLen+1;
579 // cut optional \r or \n but only when it's from another kind
580 if(nRest > nDropLen && newline[0]+newline[1]== '\r'+'\n')
581 nDropLen++;
582 }
583 else
584 {
585 if(m_Dec.get())
586 {
587 // it's the final buffer...
588 if(m_Dec->eof)
589 m_bEof=true; // won't uncompress more anyhow
590 else // otherwise has to unpack more with a larger buffer or fail
591 return GetOneLine(sOut, true);
592 }
593
594 // otherwise can continue to the finish
595 nDropLen=nLineLen=nRest;
596 }
597
598 sOut.assign(rbuf, nLineLen);
599
600 if(!m_Dec.get())
601 m_nBufPos+=nDropLen;
602 else
603 m_UncompBuf.drop(nDropLen);
604
605 m_nCurLine++;
606 return true;
607 }
608
609 #ifndef MINIBUILD
610
611 #ifdef HAVE_SSL
612 class csumSHA1 : public csumBase, public SHA_CTX
613 {
614 public:
csumSHA1()615 csumSHA1() { SHA1_Init(this); }
add(const char * data,size_t size)616 void add(const char *data, size_t size) override { SHA1_Update(this, (const void*) data, size); }
finish(uint8_t * ret)617 void finish(uint8_t* ret) override { SHA1_Final(ret, this); }
618 };
619 class csumSHA256 : public csumBase, public SHA256_CTX
620 {
621 public:
csumSHA256()622 csumSHA256() { SHA256_Init(this); }
add(const char * data,size_t size)623 void add(const char *data, size_t size) override { SHA256_Update(this, (const void*) data, size); }
finish(uint8_t * ret)624 void finish(uint8_t* ret) override { SHA256_Final(ret, this); }
625 };
626 class csumSHA512 : public csumBase, public SHA512_CTX
627 {
628 public:
csumSHA512()629 csumSHA512() { SHA512_Init(this); }
add(const char * data,size_t size)630 void add(const char *data, size_t size) override { SHA512_Update(this, (const void*) data, size); }
finish(uint8_t * ret)631 void finish(uint8_t* ret) override { SHA512_Final(ret, this); }
632 };
633 class csumMD5 : public csumBase, public MD5_CTX
634 {
635 public:
csumMD5()636 csumMD5() { MD5_Init(this); }
add(const char * data,size_t size)637 void add(const char *data, size_t size) override { MD5_Update(this, (const void*) data, size); }
finish(uint8_t * ret)638 void finish(uint8_t* ret) override { MD5_Final(ret, this); }
639 };
640 #elif defined(HAVE_TOMCRYPT)
641 class csumSHA1 : public csumBase
642 {
643 hash_state st;
644 public:
csumSHA1()645 csumSHA1() { sha1_init(&st); }
add(const char * data,size_t size)646 void add(const char *data, size_t size) override { sha1_process(&st, (const unsigned char*) data, (unsigned long) size); }
finish(uint8_t * ret)647 void finish(uint8_t* ret) override { sha1_done(&st, ret); }
648 };
649 class csumSHA256 : public csumBase
650 {
651 hash_state st;
652 public:
csumSHA256()653 csumSHA256() { sha256_init(&st); }
add(const char * data,size_t size)654 void add(const char *data, size_t size) override { sha256_process(&st, (const unsigned char*) data, (unsigned long) size); }
finish(uint8_t * ret)655 void finish(uint8_t* ret) override { sha256_done(&st, ret); }
656 };
657 class csumSHA512 : public csumBase
658 {
659 hash_state st;
660 public:
csumSHA512()661 csumSHA512() { sha512_init(&st); }
add(const char * data,size_t size)662 void add(const char *data, size_t size) override { sha512_process(&st, (const unsigned char*) data, (unsigned long) size); }
finish(uint8_t * ret)663 void finish(uint8_t* ret) override { sha512_done(&st, ret); }
664 };
665 class csumMD5 : public csumBase
666 {
667 hash_state st;
668 public:
csumMD5()669 csumMD5() { md5_init(&st); }
add(const char * data,size_t size)670 void add(const char *data, size_t size) override { md5_process(&st, (const unsigned char*) data, (unsigned long) size); }
finish(uint8_t * ret)671 void finish(uint8_t* ret) override { md5_done(&st, ret); }
672 };
673 #endif
674
675 #ifdef HAVE_CHECKSUM
GetChecker(CSTYPES type)676 std::unique_ptr<csumBase> csumBase::GetChecker(CSTYPES type)
677 {
678 switch(type)
679 {
680 case CSTYPE_MD5:
681 return std::unique_ptr<csumBase>(new csumMD5);
682 case CSTYPE_SHA1:
683 return std::unique_ptr<csumBase>(new csumSHA1);
684 case CSTYPE_SHA256:
685 return std::unique_ptr<csumBase>(new csumSHA256);
686 case CSTYPE_SHA512:
687 return std::unique_ptr<csumBase>(new csumSHA512);
688 default: // for now
689 return std::unique_ptr<csumBase>();
690 }
691 }
692 #endif
693
GetChecksum(const mstring & sFileName,int csType,uint8_t out[],bool bTryUnpack,off_t & scannedSize,FILE * fDump)694 bool filereader::GetChecksum(const mstring & sFileName, int csType, uint8_t out[],
695 bool bTryUnpack, off_t &scannedSize, FILE *fDump)
696 {
697 #ifdef HAVE_CHECKSUM
698 filereader f;
699 return (f.OpenFile(sFileName, !bTryUnpack)
700 && f.GetChecksum(csType, out, scannedSize, fDump));
701 #else
702 return false;
703 #endif
704 }
705
GetChecksum(int csType,uint8_t out[],off_t & scannedSize,FILE * fDump)706 bool filereader::GetChecksum(int csType, uint8_t out[], off_t &scannedSize, FILE *fDump)
707 {
708 #ifdef HAVE_CHECKSUM
709 unique_ptr<csumBase> summer(csumBase::GetChecker(CSTYPES(csType)));
710 scannedSize=0;
711
712 if(!m_Dec.get())
713 {
714 summer->add(m_szFileBuf, m_nBufSize);
715 //sha_update(&ctx, (SHA_BYTE*) m_szFileBuf, m_nBufSize);
716 if(fDump)
717 fwrite(m_szFileBuf, sizeof(char), m_nBufSize, fDump);
718 scannedSize=m_nBufSize;
719 }
720 else
721 {
722 for(;;)
723 {
724
725 if(!m_Dec->UncompMore(m_szFileBuf, m_nBufSize, m_nBufPos, m_UncompBuf))
726 {
727 m_bError=true;
728 return false;
729 }
730
731 unsigned nPlainSize=m_UncompBuf.size();
732 summer->add(m_UncompBuf.rptr(), nPlainSize);
733 if(fDump)
734 fwrite(m_UncompBuf.rptr(), sizeof(char), nPlainSize, fDump);
735 scannedSize+=nPlainSize;
736 m_UncompBuf.clear();
737
738 if(m_Dec->eof)
739 {
740 m_bEof=true;
741 break;
742 }
743 }
744
745 }
746 //sha_final(out, &ctx);
747 summer->finish(out);
748
749 return CheckGoodState(false);
750 #else
751 return false;
752 #endif
753 }
754
755 // test checksum wrapper classes and their algorithms, also test conversion methods
check_algos()756 void check_algos()
757 {
758 #ifdef HAVE_CHECKSUM
759 const char testvec[]="abc";
760 uint8_t out[20];
761 unique_ptr<csumBase> ap(csumBase::GetChecker(CSTYPE_SHA1));
762 ap->add(testvec, sizeof(testvec)-1);
763 ap->finish(out);
764 if(!CsEqual("a9993e364706816aba3e25717850c26c9cd0d89d", out, 20))
765 {
766 cerr << "Incorrect SHA1 implementation detected, check compilation settings!\n";
767 exit(EXIT_FAILURE);
768 }
769
770 ap = csumBase::GetChecker(CSTYPE_MD5);
771 ap->add(testvec, sizeof(testvec) - 1);
772 ap->finish(out);
773 if (BytesToHexString(out, 16) != "900150983cd24fb0d6963f7d28e17f72")
774 {
775 cerr << "Incorrect MD5 implementation detected, check compilation settings!\n";
776 exit(EXIT_FAILURE);
777 }
778 #endif
779 }
780
781
782
783 #endif
784
785 #ifdef HAVE_LIBBZ2
786
Bz2compressFile(const char * pathIn,const char * pathOut)787 bool Bz2compressFile(const char *pathIn, const char*pathOut)
788 {
789 bool bRet=false;
790 filereader reader;
791 FILE *f(nullptr);
792 BZFILE *bzf(nullptr);
793 int nError(0);
794
795 if(!reader.OpenFile(pathIn, true))
796 return false;
797
798 if(nullptr !=(f = fopen(pathOut, "w")))
799 {
800 if(!ferror(f))
801 {
802 if(nullptr != (bzf = BZ2_bzWriteOpen( &nError, f, 9, 0, 30)))
803 {
804 if(BZ_OK == nError)
805 {
806 BZ2_bzWrite(&nError, bzf, (void*) reader.GetBuffer(), reader.GetSize());
807 if(BZ_OK == nError)
808 bRet=true;
809 }
810 BZ2_bzWriteClose(&nError, bzf, 0, 0, 0);
811 if(BZ_OK != nError)
812 bRet=false;
813 }
814 }
815 if(ferror(f))
816 bRet=false;
817
818 checkForceFclose(f);
819 }
820 return bRet;
821 }
822
823 #endif
824
825 }
826