# Copyright 2001-2004 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 # $Id$ # 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 import sys,os,shutil,errno from stat import * 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.""" for x in os.listdir("."): if os.path.isdir(x): os.chdir(x) addtolist(mylist,curdir+x+"/") os.chdir("..") else: if curdir+x not in mylist: mylist.append(curdir+x) def encodeint(myint): """Takes a 4 byte integer and converts it into a string of 4 characters. Returns the characters in a string.""" part1=chr((myint >> 24 ) & 0x000000ff) part2=chr((myint >> 16 ) & 0x000000ff) part3=chr((myint >> 8 ) & 0x000000ff) part4=chr(myint & 0x000000ff) return part1+part2+part3+part4 def decodeint(mystring): """Takes a 4 byte string and converts it into a 4 byte integer. Returns an integer.""" myint=0 myint=myint+ord(mystring[3]) myint=myint+(ord(mystring[2]) << 8) myint=myint+(ord(mystring[1]) << 16) myint=myint+(ord(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.""" try: origdir=os.getcwd() except SystemExit, e: raise except: os.chdir("/") origdir="/" os.chdir(rootdir) mylist=[] addtolist(mylist,"") mylist.sort() mydata = {} for x in mylist: a = open(x, "r") mydata[x] = a.read() a.close() os.chdir(origdir) xpak_segment = xpak_mem(mydata) if outfile: outf = open(outfile, "w") outf.write(xpak_segment) outf.close() else: return xpak_segment def xpak_mem(mydata): """Create an xpack segement from a map object.""" indexglob="" indexpos=0 dataglob="" datapos=0 for x, newglob in mydata.iteritems(): 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 "XPAKPACK" \ + encodeint(len(indexglob)) \ + encodeint(len(dataglob)) \ + indexglob \ + dataglob \ + "XPAKSTOP" def xsplit(infile): """(infile) -- Splits the infile into two files. 'infile.index' contains the index segment. 'infile.dat' contails the data segment.""" myfile=open(infile,"r") mydat=myfile.read() myfile.close() splits = xsplit_mem(mydat) if not splits: return False myfile=open(infile+".index","w") myfile.write(splits[0]) myfile.close() myfile=open(infile+".dat","w") myfile.write(splits[1]) myfile.close() return True def xsplit_mem(mydat): if mydat[0:8]!="XPAKPACK": return None if mydat[-8:]!="XPAKSTOP": return None indexsize=decodeint(mydat[8:12]) datasize=decodeint(mydat[12:16]) 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(infile,"r") myheader=myfile.read(16) if myheader[0:8]!="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(infile,"r") myheader=myfile.read(16) if myheader[0:8]!="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)= 2 and len(datadir_split[1]) > 0: # This is potentially dangerous, # thus the above sanity check. try: shutil.rmtree(datadir) except OSError, 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.""" try: mystat=os.stat(self.file) if self.filestat: changed=0 for x in [ST_SIZE, ST_MTIME, ST_CTIME]: if mystat[x] != self.filestat[x]: changed=1 if not changed: return 1 self.filestat=mystat a=open(self.file,"r") a.seek(-16,2) trailer=a.read() self.infosize=0 self.xpaksize=0 if trailer[-4:]!="STOP": a.close() return 0 if trailer[0:8]!="XPAKSTOP": a.close() 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]!="XPAKPACK": a.close() 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() a.close() return 2 except SystemExit, e: raise except: return 0 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(self.file,"r") 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 try: origdir=os.getcwd() except SystemExit, e: raise except: os.chdir("/") origdir="/" a=open(self.file,"r") if not os.path.exists(mydest): os.makedirs(mydest) os.chdir(mydest) startpos=0 while ((startpos+8)