# coding=utf-8 from __future__ import absolute_import import os.path import unittest import koji import rpm SIGTAG_SIZE = 1000 try: SIGTAG_LONGSIZE = rpm.RPMTAG_LONGSIGSIZE except NameError: SIGTAG_LONGSIZE = None class TestHeaderSizes(unittest.TestCase): RPMFILES = [ "test-deps-1-1.fc24.x86_64.rpm", "test-files-1-1.fc27.noarch.rpm", "test-nosrc-1-1.fc24.nosrc.rpm", "test-deps-1-1.fc24.x86_64.rpm.signed", "test-nopatch-1-1.fc24.nosrc.rpm", "test-src-1-1.fc24.src.rpm", ] def test_header_sizes(self): for basename in self.RPMFILES: fn = os.path.join(os.path.dirname(__file__), 'data/rpms', basename) # the file length we want to match st = os.stat(fn) file_length = st.st_size # An rpm consists of: lead, signature, header, archive s_lead, s_sig = koji.find_rpm_sighdr(fn) ofs = s_lead + s_sig s_hdr = koji.rpm_hdr_size(fn, ofs) # The signature can tell use the size of header+payload # try LONGSIZE first, fall back to 32bit SIZE sighdr = koji.rip_rpm_sighdr(fn) rh = koji.RawHeader(sighdr) size = None try: tag = rpm.RPMTAG_LONGSIGSIZE size = rh.get(tag, single=True) except NameError: pass if size is None: size = rh.get(SIGTAG_SIZE, single=True) # Expected file size calc_size = s_lead + s_sig + size self.assertEqual(calc_size, file_length) # The following bit uses rpmlib to read the header, which advances the file # pointer past it. This is the same approach rpm2cpio uses. ts = rpm.TransactionSet() ts.setVSFlags(rpm._RPMVSF_NOSIGNATURES | rpm._RPMVSF_NODIGESTS | rpm.RPMVSF_NOHDRCHK) fd = os.open(fn, os.O_RDONLY) try: hdr = ts.hdrFromFdno(fd) p_offset = os.lseek(fd, 0, os.SEEK_CUR) finally: os.close(fd) expect_payload = s_lead + s_sig + s_hdr if not hdr: raise Exception("rpm did not return a header") self.assertEqual(p_offset, expect_payload)