1 /*---------------------------------------------------------------------\
3 | |__ / \ / / . \ . \ |
8 \---------------------------------------------------------------------*/
9 /** \file zypp/media/MediaBlockList.cc
13 #include <sys/types.h>
22 #include <zypp/media/MediaBlockList.h>
23 #include <zypp/base/Logger.h>
24 #include <zypp/base/String.h>
26 using namespace zypp::base;
31 MediaBlockList::MediaBlockList(off_t size)
42 MediaBlockList::addBlock(off_t off, size_t size)
45 blocks.push_back(MediaBlock( off, size ));
46 return blocks.size() - 1;
50 MediaBlockList::setFileChecksum(std::string ctype, int cl, unsigned char *c)
56 memcpy(&fsum[0], c, cl);
59 const std::vector<unsigned char> &MediaBlockList::getFileChecksum()
65 MediaBlockList::createFileDigest(Digest &digest) const
67 return digest.create(fsumtype);
71 MediaBlockList::verifyFileDigest(Digest &digest) const
73 if (!haveFileChecksum())
75 std::vector<unsigned char>dig = digest.digestVector();
76 if (dig.empty() || dig.size() < fsum.size())
78 return memcmp(&dig[0], &fsum[0], fsum.size()) ? false : true;
82 MediaBlockList::setChecksum(size_t blkno, std::string cstype, int csl, unsigned char *cs, size_t cspad)
94 if (csl != chksumlen || cstype != chksumtype || cspad != chksumpad || blkno != chksums.size() / chksumlen)
96 chksums.resize(chksums.size() + csl);
97 memcpy(&chksums[csl * blkno], cs, csl);
101 MediaBlockList::setRsum(size_t blkno, int rsl, unsigned int rs, size_t rspad)
112 if (rsl != rsumlen || rspad != rsumpad || blkno != rsums.size())
118 MediaBlockList::createDigest(Digest &digest) const
120 return digest.create(chksumtype);
124 MediaBlockList::verifyDigest(size_t blkno, Digest &digest) const
126 if (!haveChecksum(blkno))
128 size_t size = blocks[blkno].size;
131 if (chksumpad > size)
133 char pad[chksumpad - size];
134 memset(pad, 0, chksumpad - size);
135 digest.update(pad, chksumpad - size);
137 std::vector<unsigned char>dig = digest.digestVector();
138 if (dig.empty() || dig.size() < size_t(chksumlen))
140 return memcmp(&dig[0], &chksums[chksumlen * blkno], chksumlen) ? false : true;
144 MediaBlockList::updateRsum(unsigned int rs, const char* bytes, size_t len) const
149 s = (rs >> 16) & 65535;
151 for (; len > 0 ; len--)
153 unsigned short c = (unsigned char)*bytes++;
157 return (s & 65535) << 16 | (m & 65535);
161 MediaBlockList::verifyRsum(size_t blkno, unsigned int rs) const
163 if (!haveRsum(blkno))
165 size_t size = blocks[blkno].size;
171 s = (rs >> 16) & 65535;
173 m += s * (rsumpad - size);
174 rs = (s & 65535) << 16 | (m & 65535);
187 return rs == rsums[blkno];
191 MediaBlockList::checkRsum(size_t blkno, const unsigned char *buf, size_t bufl) const
193 if (blkno >= blocks.size() || bufl < blocks[blkno].size)
195 unsigned int rs = updateRsum(0, (const char *)buf, blocks[blkno].size);
196 return verifyRsum(blkno, rs);
200 MediaBlockList::checkChecksum(size_t blkno, const unsigned char *buf, size_t bufl) const
202 if (blkno >= blocks.size() || bufl < blocks[blkno].size)
205 if (!createDigest(dig))
207 dig.update((const char *)buf, blocks[blkno].size);
208 return verifyDigest(blkno, dig);
211 std::vector<unsigned char> MediaBlockList::getChecksum(size_t blkno)
213 if ( !haveChecksum(blkno) )
216 std::vector<unsigned char> buf ( chksumlen, '\0' );
217 memcpy( buf.data(), chksums.data()+(chksumlen * blkno), chksumlen );
221 // specialized version of checkChecksum that can deal with a "rotated" buffer
223 MediaBlockList::checkChecksumRotated(size_t blkno, const unsigned char *buf, size_t bufl, size_t start) const
225 if (blkno >= blocks.size() || bufl < blocks[blkno].size)
230 if (!createDigest(dig))
232 size_t size = blocks[blkno].size;
233 size_t len = bufl - start > size ? size : bufl - start;
234 dig.update((const char *)buf + start, len);
236 dig.update((const char *)buf, size - len);
237 return verifyDigest(blkno, dig);
240 // write block to the file. can also deal with "rotated" buffers
242 MediaBlockList::writeBlock(size_t blkno, FILE *fp, const unsigned char *buf, size_t bufl, size_t start, std::vector<bool> &found) const
244 if (blkno >= blocks.size() || bufl < blocks[blkno].size)
246 off_t off = blocks[blkno].off;
247 size_t size = blocks[blkno].size;
248 if (fseeko(fp, off, SEEK_SET))
252 size_t len = bufl - start > size ? size : bufl - start;
253 if (fwrite(buf + start, len, 1, fp) != 1)
255 if (size > len && fwrite(buf, size - len, 1, fp) != 1)
258 found[blocks.size()] = true;
262 fetchnext(FILE *fp, unsigned char *bp, size_t blksize, size_t pushback, unsigned char *pushbackp)
270 memmove(bp, pushbackp, pushback);
289 MediaBlockList::reuseBlocks(FILE *wfp, std::string filename)
293 if (!chksumlen || (fp = fopen(filename.c_str(), "r")) == 0)
295 size_t nblks = blocks.size();
296 std::vector<bool> found;
297 found.resize(nblks + 1);
298 if (rsumlen && !rsums.empty())
300 size_t blksize = blocks[0].size;
301 if (nblks == 1 && rsumpad && rsumpad > blksize)
303 // create hash of checksums
304 unsigned int hm = rsums.size() * 2;
305 while (hm & (hm - 1))
310 unsigned int *ht = new unsigned int[hm + 1];
311 memset(ht, 0, (hm + 1) * sizeof(unsigned int));
312 for (unsigned int i = 0; i < rsums.size(); i++)
314 if (blocks[i].size != blksize && (i != nblks - 1 || rsumpad != blksize))
316 unsigned int r = rsums[i];
317 unsigned int h = r & hm;
324 unsigned char *buf = new unsigned char[blksize];
325 unsigned char *buf2 = new unsigned char[blksize];
327 unsigned char *pushbackp = 0;
329 if ((blksize & (blksize - 1)) == 0)
330 for (bshift = 0; size_t(1 << bshift) != blksize; bshift++)
334 memset(buf, 0, blksize);
337 int sql = nblks > 1 && chksumlen < 16 ? 2 : 1;
340 for (size_t i = 0; i < blksize; i++)
366 b += a - (oc << bshift);
368 b += a - oc * blksize;
371 if (size_t(i) != blksize - 1)
377 r = ((unsigned int)b & 255);
378 else if (rsumlen == 2)
379 r = ((unsigned int)b & 65535);
380 else if (rsumlen == 3)
381 r = ((unsigned int)a & 255) << 16 | ((unsigned int)b & 65535);
383 r = ((unsigned int)a & 65535) << 16 | ((unsigned int)b & 65535);
384 unsigned int h = r & hm;
386 for (; ht[h]; h = (h + hh++) & hm)
388 size_t blkno = ht[h] - 1;
389 if (rsums[blkno] != r)
395 if (eof || blkno + 1 >= nblks)
397 pushback = fetchnext(fp, buf2, blksize, pushback, pushbackp);
401 if (!checkRsum(blkno + 1, buf2, blksize))
404 if (!checkChecksumRotated(blkno, buf, blksize, i + 1))
406 if (sql == 2 && !checkChecksum(blkno + 1, buf2, blksize))
408 writeBlock(blkno, wfp, buf, blksize, i + 1, found);
411 writeBlock(blkno + 1, wfp, buf2, blksize, 0, found);
418 pushback = fetchnext(fp, buf2, blksize, pushback, pushbackp);
422 if (!checkRsum(blkno, buf2, blksize))
424 if (!checkChecksum(blkno, buf2, blksize))
426 writeBlock(blkno, wfp, buf2, blksize, 0, found);
430 memset(buf, 0, blksize);
432 i = size_t(-1); // start with 0 on next iteration
441 else if (chksumlen >= 16)
443 // dummy variant, just check the checksums
446 unsigned char *buf = new unsigned char[bufl];
447 for (size_t blkno = 0; blkno < blocks.size(); ++blkno)
449 if (off > blocks[blkno].off)
451 size_t blksize = blocks[blkno].size;
456 buf = new unsigned char[bufl];
458 size_t skip = blocks[blkno].off - off;
461 size_t l = skip > bufl ? bufl : skip;
462 if (fread(buf, l, 1, fp) != 1)
467 if (fread(buf, blksize, 1, fp) != 1)
469 if (checkChecksum(blkno, buf, blksize))
470 writeBlock(blkno, wfp, buf, blksize, 0, found);
476 // now throw out all of the blocks we found
477 std::vector<MediaBlock> nblocks;
478 std::vector<unsigned char> nchksums;
479 std::vector<unsigned int> nrsums;
481 for (size_t blkno = 0; blkno < blocks.size(); ++blkno)
486 nblocks.push_back(blocks[blkno]);
487 if (chksumlen && (blkno + 1) * chksumlen <= chksums.size())
489 nchksums.resize(nblocks.size() * chksumlen);
490 memcpy(&nchksums[(nblocks.size() - 1) * chksumlen], &chksums[blkno * chksumlen], chksumlen);
492 if (rsumlen && (blkno + 1) <= rsums.size())
493 nrsums.push_back(rsums[blkno]);
502 MediaBlockList::asString() const
507 if (filesize != off_t(-1))
509 long long size = filesize;
510 s = zypp::str::form("[ BlockList, file size %lld\n", size);
513 s = "[ BlockList, filesize unknown\n";
515 s += " No block information\n";
517 s += zypp::str::form(" Checksum pad %zd\n", chksumpad);
519 s += zypp::str::form(" Rsum pad %zd\n", rsumpad);
520 for (i = 0; i < blocks.size(); ++i)
522 long long off=blocks[i].off;
523 long long size=blocks[i].size;
524 s += zypp::str::form(" (%8lld, %8lld)", off, size);
525 if (chksumlen && chksums.size() >= (i + 1) * chksumlen)
527 s += " " + chksumtype + ":";
528 for (j = 0; j < size_t(chksumlen); j++)
529 s += zypp::str::form("%02hhx", chksums[i * chksumlen + j]);
531 if (rsumlen && rsums.size() > i)
534 s += zypp::str::form("%0*x", 2 * rsumlen, rsums[i]);