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