diff options
author | Michał Górny <mgorny@gentoo.org> | 2018-07-17 21:50:45 +0200 |
---|---|---|
committer | Zac Medico <zmedico@gentoo.org> | 2018-07-18 16:19:11 -0700 |
commit | bc0fa8d3795ed7e40aaa00f579bb2977897bce25 (patch) | |
tree | 2a62c721ee8dec47ddb564254e1cbd967577d1f0 /pym/portage/xpak.py | |
parent | EventLoop: raise TypeError for unexpected call_* keyword args (diff) | |
download | portage-bc0fa8d3795ed7e40aaa00f579bb2977897bce25.tar.gz portage-bc0fa8d3795ed7e40aaa00f579bb2977897bce25.tar.bz2 portage-bc0fa8d3795ed7e40aaa00f579bb2977897bce25.zip |
Rename pym→lib, for better distutils-r1 interoperability
Closes: https://github.com/gentoo/portage/pull/343
Diffstat (limited to 'pym/portage/xpak.py')
-rw-r--r-- | pym/portage/xpak.py | 499 |
1 files changed, 0 insertions, 499 deletions
diff --git a/pym/portage/xpak.py b/pym/portage/xpak.py deleted file mode 100644 index e11f26e6c..000000000 --- a/pym/portage/xpak.py +++ /dev/null @@ -1,499 +0,0 @@ -# Copyright 2001-2014 Gentoo Foundation -# Distributed under the terms of the GNU General Public License v2 - - -# The format for a tbz2/xpak: -# -# tbz2: tar.bz2 + xpak + (xpak_offset) + "STOP" -# xpak: "XPAKPACK" + (index_len) + (data_len) + index + data + "XPAKSTOP" -# index: (pathname_len) + pathname + (data_offset) + (data_len) -# index entries are concatenated end-to-end. -# data: concatenated data chunks, end-to-end. -# -# [tarball]XPAKPACKIIIIDDDD[index][data]XPAKSTOPOOOOSTOP -# -# (integer) == encodeint(integer) ===> 4 characters (big-endian copy) -# '+' means concatenate the fields ===> All chunks are strings - -__all__ = [ - 'addtolist', 'decodeint', 'encodeint', 'getboth', - 'getindex', 'getindex_mem', 'getitem', 'listindex', - 'searchindex', 'tbz2', 'xpak_mem', 'xpak', 'xpand', - 'xsplit', 'xsplit_mem', -] - -import array -import errno -import sys - -import portage -from portage import os -from portage import shutil -from portage import normalize_path -from portage import _encodings -from portage import _unicode_decode -from portage import _unicode_encode - -def addtolist(mylist, curdir): - """(list, dir) --- Takes an array(list) and appends all files from dir down - the directory tree. Returns nothing. list is modified.""" - curdir = normalize_path(_unicode_decode(curdir, - encoding=_encodings['fs'], errors='strict')) - for parent, dirs, files in os.walk(curdir): - - parent = _unicode_decode(parent, - encoding=_encodings['fs'], errors='strict') - if parent != curdir: - mylist.append(parent[len(curdir) + 1:] + os.sep) - - for x in dirs: - try: - _unicode_decode(x, encoding=_encodings['fs'], errors='strict') - except UnicodeDecodeError: - dirs.remove(x) - - for x in files: - try: - x = _unicode_decode(x, - encoding=_encodings['fs'], errors='strict') - except UnicodeDecodeError: - continue - mylist.append(os.path.join(parent, x)[len(curdir) + 1:]) - -def encodeint(myint): - """Takes a 4 byte integer and converts it into a string of 4 characters. - Returns the characters in a string.""" - a = array.array('B') - a.append((myint >> 24) & 0xff) - a.append((myint >> 16) & 0xff) - a.append((myint >> 8) & 0xff) - a.append(myint & 0xff) - try: - # Python >= 3.2 - return a.tobytes() - except AttributeError: - return a.tostring() - -def decodeint(mystring): - """Takes a 4 byte string and converts it into a 4 byte integer. - Returns an integer.""" - if sys.hexversion < 0x3000000: - mystring = [ord(x) for x in mystring] - myint = 0 - myint += mystring[3] - myint += mystring[2] << 8 - myint += mystring[1] << 16 - myint += mystring[0] << 24 - return myint - -def xpak(rootdir, outfile=None): - """(rootdir, outfile) -- creates an xpak segment of the directory 'rootdir' - and under the name 'outfile' if it is specified. Otherwise it returns the - xpak segment.""" - - mylist = [] - - addtolist(mylist, rootdir) - mylist.sort() - mydata = {} - for x in mylist: - if x == 'CONTENTS': - # CONTENTS is generated during the merge process. - continue - x = _unicode_encode(x, encoding=_encodings['fs'], errors='strict') - with open(os.path.join(rootdir, x), 'rb') as f: - mydata[x] = f.read() - - xpak_segment = xpak_mem(mydata) - if outfile: - outf = open(_unicode_encode(outfile, - encoding=_encodings['fs'], errors='strict'), 'wb') - outf.write(xpak_segment) - outf.close() - else: - return xpak_segment - -def xpak_mem(mydata): - """Create an xpack segment from a map object.""" - - mydata_encoded = {} - for k, v in mydata.items(): - k = _unicode_encode(k, - encoding=_encodings['repo.content'], errors='backslashreplace') - v = _unicode_encode(v, - encoding=_encodings['repo.content'], errors='backslashreplace') - mydata_encoded[k] = v - mydata = mydata_encoded - del mydata_encoded - - indexglob = b'' - indexpos = 0 - dataglob = b'' - datapos = 0 - for x, newglob in mydata.items(): - mydatasize = len(newglob) - indexglob = indexglob + encodeint(len(x)) + x + encodeint(datapos) + encodeint(mydatasize) - indexpos = indexpos + 4 + len(x) + 4 + 4 - dataglob = dataglob + newglob - datapos = datapos + mydatasize - return b'XPAKPACK' \ - + encodeint(len(indexglob)) \ - + encodeint(len(dataglob)) \ - + indexglob \ - + dataglob \ - + b'XPAKSTOP' - -def xsplit(infile): - """(infile) -- Splits the infile into two files. - 'infile.index' contains the index segment. - 'infile.dat' contails the data segment.""" - infile = _unicode_decode(infile, - encoding=_encodings['fs'], errors='strict') - myfile = open(_unicode_encode(infile, - encoding=_encodings['fs'], errors='strict'), 'rb') - mydat = myfile.read() - myfile.close() - - splits = xsplit_mem(mydat) - if not splits: - return False - - myfile = open(_unicode_encode(infile + '.index', - encoding=_encodings['fs'], errors='strict'), 'wb') - myfile.write(splits[0]) - myfile.close() - myfile = open(_unicode_encode(infile + '.dat', - encoding=_encodings['fs'], errors='strict'), 'wb') - myfile.write(splits[1]) - myfile.close() - return True - -def xsplit_mem(mydat): - if mydat[0:8] != b'XPAKPACK': - return None - if mydat[-8:] != b'XPAKSTOP': - return None - indexsize = decodeint(mydat[8:12]) - return (mydat[16:indexsize + 16], mydat[indexsize + 16:-8]) - -def getindex(infile): - """(infile) -- grabs the index segment from the infile and returns it.""" - myfile = open(_unicode_encode(infile, - encoding=_encodings['fs'], errors='strict'), 'rb') - myheader = myfile.read(16) - if myheader[0:8] != b'XPAKPACK': - myfile.close() - return - indexsize = decodeint(myheader[8:12]) - myindex = myfile.read(indexsize) - myfile.close() - return myindex - -def getboth(infile): - """(infile) -- grabs the index and data segments from the infile. - Returns an array [indexSegment, dataSegment]""" - myfile = open(_unicode_encode(infile, - encoding=_encodings['fs'], errors='strict'), 'rb') - myheader = myfile.read(16) - if myheader[0:8] != b'XPAKPACK': - myfile.close() - return - indexsize = decodeint(myheader[8:12]) - datasize = decodeint(myheader[12:16]) - myindex = myfile.read(indexsize) - mydata = myfile.read(datasize) - myfile.close() - return myindex, mydata - -def listindex(myindex): - """Print to the terminal the filenames listed in the indexglob passed in.""" - for x in getindex_mem(myindex): - print(x) - -def getindex_mem(myindex): - """Returns the filenames listed in the indexglob passed in.""" - myindexlen = len(myindex) - startpos = 0 - myret = [] - while ((startpos + 8) < myindexlen): - mytestlen = decodeint(myindex[startpos:startpos + 4]) - myret = myret + [myindex[startpos + 4:startpos + 4 + mytestlen]] - startpos = startpos + mytestlen + 12 - return myret - -def searchindex(myindex, myitem): - """(index, item) -- Finds the offset and length of the file 'item' in the - datasegment via the index 'index' provided.""" - myitem = _unicode_encode(myitem, - encoding=_encodings['repo.content'], errors='backslashreplace') - mylen = len(myitem) - myindexlen = len(myindex) - startpos = 0 - while ((startpos + 8) < myindexlen): - mytestlen = decodeint(myindex[startpos:startpos + 4]) - if mytestlen == mylen: - if myitem == myindex[startpos + 4:startpos + 4 + mytestlen]: - #found - datapos = decodeint(myindex[startpos + 4 + mytestlen:startpos + 8 + mytestlen]) - datalen = decodeint(myindex[startpos + 8 + mytestlen:startpos + 12 + mytestlen]) - return datapos, datalen - startpos = startpos + mytestlen + 12 - -def getitem(myid, myitem): - myindex = myid[0] - mydata = myid[1] - myloc = searchindex(myindex, myitem) - if not myloc: - return None - return mydata[myloc[0]:myloc[0] + myloc[1]] - -def xpand(myid, mydest): - mydest = normalize_path(mydest) + os.sep - myindex = myid[0] - mydata = myid[1] - myindexlen = len(myindex) - startpos = 0 - while ((startpos + 8) < myindexlen): - namelen = decodeint(myindex[startpos:startpos + 4]) - datapos = decodeint(myindex[startpos + 4 + namelen:startpos + 8 + namelen]) - datalen = decodeint(myindex[startpos + 8 + namelen:startpos + 12 + namelen]) - myname = myindex[startpos + 4:startpos + 4 + namelen] - myname = _unicode_decode(myname, - encoding=_encodings['repo.content'], errors='replace') - filename = os.path.join(mydest, myname.lstrip(os.sep)) - filename = normalize_path(filename) - if not filename.startswith(mydest): - # myname contains invalid ../ component(s) - continue - dirname = os.path.dirname(filename) - if dirname: - if not os.path.exists(dirname): - os.makedirs(dirname) - mydat = open(_unicode_encode(filename, - encoding=_encodings['fs'], errors='strict'), 'wb') - mydat.write(mydata[datapos:datapos + datalen]) - mydat.close() - startpos = startpos + namelen + 12 - -class tbz2(object): - def __init__(self, myfile): - self.file = myfile - self.filestat = None - self.index = b'' - self.infosize = 0 - self.xpaksize = 0 - self.indexsize = None - self.datasize = None - self.indexpos = None - self.datapos = None - - def decompose(self, datadir, cleanup=1): - """Alias for unpackinfo() --- Complement to recompose() but optionally - deletes the destination directory. Extracts the xpak from the tbz2 into - the directory provided. Raises IOError if scan() fails. - Returns result of upackinfo().""" - if not self.scan(): - raise IOError - if cleanup: - self.cleanup(datadir) - if not os.path.exists(datadir): - os.makedirs(datadir) - return self.unpackinfo(datadir) - def compose(self, datadir, cleanup=0): - """Alias for recompose().""" - return self.recompose(datadir, cleanup) - - def recompose(self, datadir, cleanup=0, break_hardlinks=True): - """Creates an xpak segment from the datadir provided, truncates the tbz2 - to the end of regular data if an xpak segment already exists, and adds - the new segment to the file with terminating info.""" - xpdata = xpak(datadir) - self.recompose_mem(xpdata, break_hardlinks=break_hardlinks) - if cleanup: - self.cleanup(datadir) - - def recompose_mem(self, xpdata, break_hardlinks=True): - """ - Update the xpak segment. - @param xpdata: A new xpak segment to be written, like that returned - from the xpak_mem() function. - @param break_hardlinks: If hardlinks exist, create a copy in order - to break them. This makes it safe to use hardlinks to create - cheap snapshots of the repository, which is useful for solving - race conditions on binhosts as described here: - https://crbug.com/185031 - Default is True. - """ - self.scan() # Don't care about condition... We'll rewrite the data anyway. - - if break_hardlinks and self.filestat and self.filestat.st_nlink > 1: - tmp_fname = "%s.%d" % (self.file, os.getpid()) - shutil.copyfile(self.file, tmp_fname) - try: - portage.util.apply_stat_permissions(self.file, self.filestat) - except portage.exception.OperationNotPermitted: - pass - os.rename(tmp_fname, self.file) - - myfile = open(_unicode_encode(self.file, - encoding=_encodings['fs'], errors='strict'), 'ab+') - if not myfile: - raise IOError - myfile.seek(-self.xpaksize, 2) # 0,2 or -0,2 just mean EOF. - myfile.truncate() - myfile.write(xpdata + encodeint(len(xpdata)) + b'STOP') - myfile.flush() - myfile.close() - return 1 - - def cleanup(self, datadir): - datadir_split = os.path.split(datadir) - if len(datadir_split) >= 2 and len(datadir_split[1]) > 0: - # This is potentially dangerous, - # thus the above sanity check. - try: - shutil.rmtree(datadir) - except OSError as oe: - if oe.errno == errno.ENOENT: - pass - else: - raise oe - - def scan(self): - """Scans the tbz2 to locate the xpak segment and setup internal values. - This function is called by relevant functions already.""" - a = None - try: - mystat = os.stat(self.file) - if self.filestat: - changed = 0 - if mystat.st_size != self.filestat.st_size \ - or mystat.st_mtime != self.filestat.st_mtime \ - or mystat.st_ctime != self.filestat.st_ctime: - changed = True - if not changed: - return 1 - self.filestat = mystat - a = open(_unicode_encode(self.file, - encoding=_encodings['fs'], errors='strict'), 'rb') - a.seek(-16, 2) - trailer = a.read() - self.infosize = 0 - self.xpaksize = 0 - if trailer[-4:] != b'STOP': - return 0 - if trailer[0:8] != b'XPAKSTOP': - return 0 - self.infosize = decodeint(trailer[8:12]) - self.xpaksize = self.infosize + 8 - a.seek(-(self.xpaksize), 2) - header = a.read(16) - if header[0:8] != b'XPAKPACK': - return 0 - self.indexsize = decodeint(header[8:12]) - self.datasize = decodeint(header[12:16]) - self.indexpos = a.tell() - self.index = a.read(self.indexsize) - self.datapos = a.tell() - return 2 - except SystemExit: - raise - except: - return 0 - finally: - if a is not None: - a.close() - - def filelist(self): - """Return an array of each file listed in the index.""" - if not self.scan(): - return None - return getindex_mem(self.index) - - def getfile(self, myfile, mydefault=None): - """Finds 'myfile' in the data segment and returns it.""" - if not self.scan(): - return None - myresult = searchindex(self.index, myfile) - if not myresult: - return mydefault - a = open(_unicode_encode(self.file, - encoding=_encodings['fs'], errors='strict'), 'rb') - a.seek(self.datapos + myresult[0], 0) - myreturn = a.read(myresult[1]) - a.close() - return myreturn - - def getelements(self, myfile): - """A split/array representation of tbz2.getfile()""" - mydat = self.getfile(myfile) - if not mydat: - return [] - return mydat.split() - - def unpackinfo(self, mydest): - """Unpacks all the files from the dataSegment into 'mydest'.""" - if not self.scan(): - return 0 - mydest = normalize_path(mydest) + os.sep - a = open(_unicode_encode(self.file, - encoding=_encodings['fs'], errors='strict'), 'rb') - if not os.path.exists(mydest): - os.makedirs(mydest) - startpos = 0 - while ((startpos + 8) < self.indexsize): - namelen = decodeint(self.index[startpos:startpos + 4]) - datapos = decodeint(self.index[startpos + 4 + namelen:startpos + 8 + namelen]) - datalen = decodeint(self.index[startpos + 8 + namelen:startpos + 12 + namelen]) - myname = self.index[startpos + 4:startpos + 4 + namelen] - myname = _unicode_decode(myname, - encoding=_encodings['repo.content'], errors='replace') - filename = os.path.join(mydest, myname.lstrip(os.sep)) - filename = normalize_path(filename) - if not filename.startswith(mydest): - # myname contains invalid ../ component(s) - continue - dirname = os.path.dirname(filename) - if dirname: - if not os.path.exists(dirname): - os.makedirs(dirname) - mydat = open(_unicode_encode(filename, - encoding=_encodings['fs'], errors='strict'), 'wb') - a.seek(self.datapos + datapos) - mydat.write(a.read(datalen)) - mydat.close() - startpos = startpos + namelen + 12 - a.close() - return 1 - - def get_data(self): - """Returns all the files from the dataSegment as a map object.""" - if not self.scan(): - return {} - a = open(_unicode_encode(self.file, - encoding=_encodings['fs'], errors='strict'), 'rb') - mydata = {} - startpos = 0 - while ((startpos + 8) < self.indexsize): - namelen = decodeint(self.index[startpos:startpos + 4]) - datapos = decodeint(self.index[startpos + 4 + namelen:startpos + 8 + namelen]) - datalen = decodeint(self.index[startpos + 8 + namelen:startpos + 12 + namelen]) - myname = self.index[startpos + 4:startpos + 4 + namelen] - a.seek(self.datapos + datapos) - mydata[myname] = a.read(datalen) - startpos = startpos + namelen + 12 - a.close() - return mydata - - def getboth(self): - """Returns an array [indexSegment, dataSegment]""" - if not self.scan(): - return None - - a = open(_unicode_encode(self.file, - encoding=_encodings['fs'], errors='strict'), 'rb') - a.seek(self.datapos) - mydata = a.read(self.datasize) - a.close() - - return self.index, mydata |