def __readIndex(self, pad): """Read and verify header index and data. self.fd should already be open. Return (number of tags, tag data size, header header, index data, data area, total header size). Discard data to enforce alignment at least pad. Raise ValueError on invalid data, IOError.""" data = functions.readExact(self.fd, 16) (magic, indexNo, storeSize) = unpack("!8s2I", data) if magic != RPM_HEADER_INDEX_MAGIC or indexNo < 1: raise ValueError, "bad index magic" fmt = functions.readExact(self.fd, 16 * indexNo) fmt2 = functions.readExact(self.fd, storeSize) if pad != 1: functions.readExact(self.fd, (pad - (storeSize % pad)) % pad) return (indexNo, storeSize, data, fmt, fmt2, 16 + len(fmt) + len(fmt2))
def read(self, size): """Return up to size bytes of file data. Raise IOError.""" if size > self.lastfilesize - self.readsize: size = self.lastfilesize - self.readsize self.readsize += size return functions.readExact(self.fd, size)
def __readLead(self): """Read lead. self.fd should already be open. Raise ValueError on invalid data, IOError.""" leaddata = functions.readExact(self.fd, 96) if leaddata[:4] != RPM_HEADER_LEAD_MAGIC: raise ValueError, "no rpm magic found" self.issrc = (leaddata[7] == "\01") return ("magic", leaddata[:4])
def __init__(self, filename): """Open an ELF file filename. Raise IOError, ValueError on invalid (or non-ELF) input.""" self.filename = filename self.fd = open(filename) (magic, data_size, encoding, version) = \ struct.unpack("4s3B9x", functions.readExact(self.fd, 16)) if magic != _ELFMAG: raise ValueError, "%s: Not an ELF file" % filename if version != _EV_CURRENT: raise ValueError, \ "%s: Unknown ELF version %s" % (filename, version) if data_size == _ELFCLASS32: self.b64 = False elif data_size == _ELFCLASS64: self.b64 = True else: raise ValueError, \ "%s: Unknown data size %s" % (filename, data_size) if encoding == _ELFDATA2LSB: self.endian_prefix = '<' elif encoding == _ELFDATA2MSB: self.endian_prefix = '>' else: raise ValueError, \ "%s: Unknown data encoding %s" % (filename, encoding) if not self.b64: tuple_ = self._readAndUnpack("H10xI10x2H6x") else: tuple_ = self._readAndUnpack("H14xQ14x2H6x") (self.type, ph_offset, ph_size, num_ph) = tuple_ if ph_size != _ELFPhdr.entry_size[self.b64]: raise ValueError, \ ("%s: Unhandled program header size %s" % (filename, ph_size)) self.fd.seek(ph_offset) self.phdrs = [] for _ in xrange(num_ph): self.phdrs.append(_ELFPhdr(self)) self.dynamic = [] dynamics = [phdr for phdr in self.phdrs if phdr.type == _ELFPhdr.PT_DYNAMIC] if dynamics: if len(dynamics) > 1: raise ValueError, \ "%s: More than one dynamic section" % filename dynamic = dynamics[0] self.fd.seek(dynamic.offset) if dynamic.filesz % _ELFDynamic.entry_size[self.b64] != 0: raise ValueError, "%s: Invalid dynamic section size" % filename for _ in xrange(dynamic.filesz / _ELFDynamic.entry_size[self.b64]): self.dynamic.append(_ELFDynamic(self))
def _readAndUnpack(self, format): """Read data from self.fd and extract it as described by format. Raise IOError, ValueError on invalid input.""" format = self.endian_prefix + format data = functions.readExact(self.fd, struct.calcsize(format)) try: res = struct.unpack(format, data) except struct.error: raise ValueError, "%s: Error unpacking data" % self.filename return res
def getNextEntry(self): """Read next header and contents, return (file name, file data length), or (None, None) at EOF. Metadata is discarded. Raise IOError.""" self.readsize = 0 # Do padding if necessary for nexty entry functions.readExact(self.fd, (4 - (self.lastfilesize % 4)) % 4) # The cpio header contains 8 byte hex numbers with the following # content: magic, inode, mode, uid, gid, nlink, mtime, filesize, # devMajor, devMinor, rdevMajor, rdevMinor, namesize, checksum. data = functions.readExact(self.fd, 110) # CPIO ASCII hex, expanded device numbers (070702 with CRC) if data[0:6] not in ["070701", "070702"]: raise IOError, "Bad magic reading CPIO headers %s" % data[0:6] # Read filename and padding. filenamesize = int(data[94:102], 16) filename = functions.readExact(self.fd, filenamesize).rstrip("\x00") functions.readExact(self.fd, (4 - ((110 + filenamesize) % 4)) % 4) if filename == "TRAILER!!!": # end of archive detection return (None, None) # Adjust filename, so that it matches the way the rpm header has # filenames stored. This code used to be: # 'filename = "/" + os.path.normpath("./" + filename)' if filename[:2] == "./": filename = filename[1:] if filename[:1] != "/": filename = "%s%s" % ("/", filename) if filename[-1:] == "/" and len(filename) > 1: filename = filename[:-1] # Read file contents. self.lastfilesize = int(data[54:62], 16) return (filename, self.lastfilesize)