Package entropy :: Package spm :: Package plugins :: Package interfaces :: Package portage_plugin :: Module xpak

Source Code for Module entropy.spm.plugins.interfaces.portage_plugin.xpak

  1  # -*- coding: utf-8 -*- 
  2  # Copyright 2001-2004 Gentoo Foundation 
  3  # Distributed under the terms of the GNU General Public License v2 
  4  # $Id: xpak.py 5595 2007-01-12 08:08:03Z antarus $ 
  5   
  6   
  7  # The format for a tbz2/xpak: 
  8  # 
  9  #  tbz2: tar.bz2 + xpak + (xpak_offset) + "STOP" 
 10  #  xpak: "XPAKPACK" + (index_len) + (data_len) + index + data + "XPAKSTOP" 
 11  # index: (pathname_len) + pathname + (data_offset) + (data_len) 
 12  #        index entries are concatenated end-to-end. 
 13  #  data: concatenated data chunks, end-to-end. 
 14  # 
 15  # [tarball]XPAKPACKIIIIDDDD[index][data]XPAKSTOPOOOOSTOP 
 16  # 
 17  # (integer) == encodeint(integer)  ===> 4 characters (big-endian copy) 
 18  # '+' means concatenate the fields ===> All chunks are strings 
 19   
 20  import sys 
 21  import os, shutil, errno 
 22  from stat import * 
 23   
 24  if sys.hexversion >= 0x3000000: 
 25      XPAKPACK = b"XPAKPACK" 
 26      XPAKSTOP = b"XPAKSTOP" 
 27      STOP = b"STOP" 
 28  else: 
 29      XPAKPACK = "XPAKPACK" 
 30      XPAKSTOP = "XPAKSTOP" 
 31      STOP = "STOP" 
 32   
33 -def addtolist(mylist, curdir):
34 """(list, dir) --- Takes an array(list) and appends all files from dir down 35 the directory tree. Returns nothing. list is modified.""" 36 if sys.hexversion >= 0x3000000: 37 this_dir = b"." 38 slash_dir = b"/" 39 upper_dir = b".." 40 else: 41 this_dir = "." 42 slash_dir = "/" 43 upper_dir = ".." 44 for x in os.listdir(this_dir): 45 if os.path.isdir(x): 46 os.chdir(x) 47 addtolist(mylist, curdir + x + slash_dir) 48 os.chdir(upper_dir) 49 else: 50 if curdir+x not in mylist: 51 mylist.append(curdir+x)
52
53 -def encodeint(myint):
54 """Takes a 4 byte integer and converts it into a string of 4 characters. 55 Returns the characters in a string.""" 56 part1=chr((myint >> 24 ) & 0x000000ff) 57 part2=chr((myint >> 16 ) & 0x000000ff) 58 part3=chr((myint >> 8 ) & 0x000000ff) 59 part4=chr(myint & 0x000000ff) 60 if sys.hexversion >= 0x3000000: 61 return bytes(part1+part2+part3+part4, 'raw_unicode_escape') 62 else: 63 return part1+part2+part3+part4
64
65 -def decodeint(mystring):
66 """Takes a 4 byte string and converts it into a 4 byte integer. 67 Returns an integer.""" 68 myint=0 69 if sys.hexversion >= 0x3000000: 70 myint=myint+mystring[3] 71 myint=myint+(mystring[2] << 8) 72 myint=myint+(mystring[1] << 16) 73 myint=myint+(mystring[0] << 24) 74 else: 75 myint=myint+ord(mystring[3]) 76 myint=myint+(ord(mystring[2]) << 8) 77 myint=myint+(ord(mystring[1]) << 16) 78 myint=myint+(ord(mystring[0]) << 24) 79 return myint
80
81 -def xpak(rootdir,outfile=None):
82 """(rootdir,outfile) -- creates an xpak segment of the directory 'rootdir' 83 and under the name 'outfile' if it is specified. Otherwise it returns the 84 xpak segment.""" 85 try: 86 origdir=os.getcwd() 87 except SystemExit: 88 raise 89 except: 90 os.chdir("/") 91 origdir="/" 92 os.chdir(rootdir) 93 mylist = [] 94 95 if sys.hexversion >= 0x3000000: 96 edir = b"" 97 else: 98 edir = "" 99 100 addtolist(mylist, edir) 101 102 mylist.sort() 103 mydata = {} 104 for x in mylist: 105 a = open(x, "rb") 106 mydata[x] = a.read() 107 a.close() 108 os.chdir(origdir) 109 110 xpak_segment = xpak_mem(mydata) 111 if outfile: 112 outf = open(outfile, "wb") 113 outf.write(xpak_segment) 114 outf.close() 115 else: 116 return xpak_segment
117
118 -def xpak_mem(mydata):
119 """Create an xpack segement from a map object.""" 120 if sys.hexversion >= 0x3000000: 121 indexglob = b"" 122 dataglob = b"" 123 else: 124 indexglob = "" 125 dataglob = "" 126 indexpos = 0 127 datapos = 0 128 129 for x, newglob in mydata.items(): 130 mydatasize = len(newglob) 131 int_enc_dir = encodeint(len(x)) + x 132 indexglob += int_enc_dir + encodeint(datapos) + encodeint(mydatasize) 133 indexpos = indexpos + 4 + len(x) + 4 + 4 134 dataglob = dataglob + newglob 135 datapos += mydatasize 136 return XPAKPACK \ 137 + encodeint(len(indexglob)) \ 138 + encodeint(len(dataglob)) \ 139 + indexglob \ 140 + dataglob \ 141 + XPAKSTOP
142
143 -def xsplit(infile):
144 """(infile) -- Splits the infile into two files. 145 'infile.index' contains the index segment. 146 'infile.dat' contails the data segment.""" 147 myfile=open(infile, "rb") 148 mydat=myfile.read() 149 myfile.close() 150 151 splits = xsplit_mem(mydat) 152 if not splits: 153 return False 154 155 myfile=open(infile+".index", "wb") 156 myfile.write(splits[0]) 157 myfile.close() 158 myfile=open(infile+".dat", "wb") 159 myfile.write(splits[1]) 160 myfile.close() 161 return True
162
163 -def xsplit_mem(mydat):
164 if mydat[0:8] != XPAKPACK: 165 return None 166 if mydat[-8:] != XPAKSTOP: 167 return None 168 indexsize=decodeint(mydat[8:12]) 169 #datasize=decodeint(mydat[12:16]) not used 170 return (mydat[16:indexsize+16], mydat[indexsize+16:-8])
171
172 -def getindex(infile):
173 """(infile) -- grabs the index segment from the infile and returns it.""" 174 myfile=open(infile, "rb") 175 myheader=myfile.read(16) 176 if myheader[0:8] != XPAKPACK: 177 myfile.close() 178 return 179 indexsize=decodeint(myheader[8:12]) 180 myindex=myfile.read(indexsize) 181 myfile.close() 182 return myindex
183
184 -def getboth(infile):
185 """(infile) -- grabs the index and data segments from the infile. 186 Returns an array [indexSegment,dataSegment]""" 187 myfile=open(infile, "rb") 188 myheader=myfile.read(16) 189 if myheader[0:8] != XPAKPACK: 190 myfile.close() 191 return 192 indexsize=decodeint(myheader[8:12]) 193 datasize=decodeint(myheader[12:16]) 194 myindex=myfile.read(indexsize) 195 mydata=myfile.read(datasize) 196 myfile.close() 197 return myindex, mydata
198
199 -def listindex(myindex):
200 """Print to the terminal the filenames listed in the indexglob passed in.""" 201 for x in getindex_mem(myindex): 202 print(x)
203
204 -def getindex_mem(myindex):
205 """Returns the filenames listed in the indexglob passed in.""" 206 myindexlen=len(myindex) 207 startpos=0 208 myret=[] 209 while ((startpos+8)<myindexlen): 210 mytestlen=decodeint(myindex[startpos:startpos+4]) 211 myret=myret+[myindex[startpos+4:startpos+4+mytestlen]] 212 startpos=startpos+mytestlen+12 213 return myret
214
215 -def searchindex(myindex, myitem):
216 """(index,item) -- Finds the offset and length of the file 'item' in the 217 datasegment via the index 'index' provided.""" 218 mylen=len(myitem) 219 myindexlen=len(myindex) 220 startpos=0 221 while ((startpos+8)<myindexlen): 222 mytestlen=decodeint(myindex[startpos:startpos+4]) 223 if mytestlen==mylen: 224 if myitem==myindex[startpos+4:startpos+4+mytestlen]: 225 #found 226 datapos=decodeint(myindex[startpos+4+mytestlen:startpos+8+mytestlen]); 227 datalen=decodeint(myindex[startpos+8+mytestlen:startpos+12+mytestlen]); 228 return datapos, datalen 229 startpos=startpos+mytestlen+12
230
231 -def getitem(myid, myitem):
232 myindex=myid[0] 233 mydata=myid[1] 234 myloc=searchindex(myindex, myitem) 235 if not myloc: 236 return None 237 return mydata[myloc[0]:myloc[0]+myloc[1]]
238
239 -def xpand(myid, mydest):
240 myindex=myid[0] 241 mydata=myid[1] 242 try: 243 origdir=os.getcwd() 244 except SystemExit: 245 raise 246 except: 247 os.chdir("/") 248 origdir="/" 249 os.chdir(mydest) 250 myindexlen=len(myindex) 251 startpos=0 252 while ((startpos+8)<myindexlen): 253 namelen=decodeint(myindex[startpos:startpos+4]) 254 datapos=decodeint(myindex[startpos+4+namelen:startpos+8+namelen]); 255 datalen=decodeint(myindex[startpos+8+namelen:startpos+12+namelen]); 256 myname=myindex[startpos+4:startpos+4+namelen] 257 dirname=os.path.dirname(myname) 258 if dirname: 259 if not os.path.exists(dirname): 260 os.makedirs(dirname) 261 mydat=open(myname, "wb") 262 mydat.write(mydata[datapos:datapos+datalen]) 263 mydat.close() 264 startpos=startpos+namelen+12 265 os.chdir(origdir)
266
267 -class tbz2:
268 - def __init__(self, myfile):
269 self.file=myfile 270 self.filestat=None 271 self.index="" 272 self.infosize=0 273 self.xpaksize=0 274 self.indexsize=None 275 self.datasize=None 276 self.indexpos=None 277 self.datapos=None 278 self.scan()
279
280 - def decompose(self,datadir,cleanup=1):
281 """Alias for unpackinfo() --- Complement to recompose() but optionally 282 deletes the destination directory. Extracts the xpak from the tbz2 into 283 the directory provided. Raises IOError if scan() fails. 284 Returns result of upackinfo().""" 285 if not self.scan(): 286 raise IOError 287 if cleanup: 288 self.cleanup(datadir) 289 if not os.path.exists(datadir): 290 os.makedirs(datadir) 291 return self.unpackinfo(datadir)
292
293 - def compose(self, datadir, cleanup=0):
294 """Alias for recompose().""" 295 return self.recompose(datadir, cleanup)
296
297 - def recompose(self, datadir, cleanup=0):
298 """Creates an xpak segment from the datadir provided, truncates the tbz2 299 to the end of regular data if an xpak segment already exists, and adds 300 the new segment to the file with terminating info.""" 301 xpdata = xpak(datadir) 302 self.recompose_mem(xpdata) 303 if cleanup: 304 self.cleanup(datadir)
305
306 - def recompose_mem(self, xpdata):
307 self.scan() # Don't care about condition... We'll rewrite the data anyway. 308 myfile=open(self.file, "ab+") 309 if not myfile: 310 raise IOError 311 myfile.seek(-self.xpaksize, os.SEEK_END) # 0,2 or -0,2 just mean EOF. 312 myfile.truncate() 313 myfile.write(xpdata+encodeint(len(xpdata))+STOP) 314 myfile.flush() 315 myfile.close() 316 return 1
317
318 - def cleanup(self, datadir):
319 datadir_split = os.path.split(datadir) 320 if len(datadir_split) >= 2 and len(datadir_split[1]) > 0: 321 # This is potentially dangerous, 322 # thus the above sanity check. 323 try: 324 shutil.rmtree(datadir) 325 except OSError as oe: 326 if oe.errno == errno.ENOENT: 327 pass 328 else: 329 raise oe
330
331 - def scan(self):
332 """Scans the tbz2 to locate the xpak segment and setup internal values. 333 This function is called by relevant functions already.""" 334 try: 335 mystat=os.stat(self.file) 336 if self.filestat: 337 changed=0 338 for x in [ST_SIZE, ST_MTIME, ST_CTIME]: 339 if mystat[x] != self.filestat[x]: 340 changed=1 341 if not changed: 342 return 1 343 self.filestat=mystat 344 a=open(self.file, "rb") 345 a.seek(-16, os.SEEK_END) 346 trailer=a.read() 347 self.infosize=0 348 self.xpaksize=0 349 if trailer[-4:]!=STOP: 350 a.close() 351 return 0 352 if trailer[0:8]!=XPAKSTOP: 353 a.close() 354 return 0 355 self.infosize=decodeint(trailer[8:12]) 356 self.xpaksize=self.infosize+8 357 a.seek(-(self.xpaksize), os.SEEK_END) 358 header=a.read(16) 359 if header[0:8]!=XPAKPACK: 360 a.close() 361 return 0 362 self.indexsize=decodeint(header[8:12]) 363 self.datasize=decodeint(header[12:16]) 364 self.indexpos=a.tell() 365 self.index=a.read(self.indexsize) 366 self.datapos=a.tell() 367 a.close() 368 return 2 369 except SystemExit: 370 raise 371 except: 372 return 0
373
374 - def filelist(self):
375 """Return an array of each file listed in the index.""" 376 if not self.scan(): 377 return None 378 return getindex_mem(self.index)
379
380 - def getfile(self,myfile,mydefault=None):
381 """Finds 'myfile' in the data segment and returns it.""" 382 if not self.scan(): 383 return None 384 myresult=searchindex(self.index, myfile) 385 if not myresult: 386 return mydefault 387 a=open(self.file, "rb") 388 a.seek(self.datapos+myresult[0], 0) 389 myreturn=a.read(myresult[1]) 390 a.close() 391 return myreturn
392
393 - def getelements(self, myfile):
394 """A split/array representation of tbz2.getfile()""" 395 mydat=self.getfile(myfile) 396 if not mydat: 397 return [] 398 return mydat.split()
399
400 - def unpackinfo(self, mydest):
401 """Unpacks all the files from the dataSegment into 'mydest'.""" 402 if not self.scan(): 403 return 0 404 try: 405 origdir=os.getcwd() 406 except SystemExit: 407 raise 408 except: 409 os.chdir("/") 410 origdir="/" 411 a=open(self.file, "rb") 412 if not os.path.exists(mydest): 413 os.makedirs(mydest) 414 os.chdir(mydest) 415 startpos=0 416 while ((startpos+8)<self.indexsize): 417 namelen=decodeint(self.index[startpos:startpos+4]) 418 datapos=decodeint(self.index[startpos+4+namelen:startpos+8+namelen]); 419 datalen=decodeint(self.index[startpos+8+namelen:startpos+12+namelen]); 420 myname=self.index[startpos+4:startpos+4+namelen] 421 dirname=os.path.dirname(myname) 422 if dirname: 423 if not os.path.exists(dirname): 424 os.makedirs(dirname) 425 mydat=open(myname, "wb") 426 a.seek(self.datapos+datapos) 427 mydat.write(a.read(datalen)) 428 mydat.close() 429 startpos=startpos+namelen+12 430 a.close() 431 os.chdir(origdir) 432 return 1
433
434 - def get_data(self):
435 """Returns all the files from the dataSegment as a map object.""" 436 if not self.scan(): 437 return 0 438 a = open(self.file, "rb") 439 mydata = {} 440 startpos=0 441 while ((startpos+8)<self.indexsize): 442 namelen=decodeint(self.index[startpos:startpos+4]) 443 datapos=decodeint(self.index[startpos+4+namelen:startpos+8+namelen]); 444 datalen=decodeint(self.index[startpos+8+namelen:startpos+12+namelen]); 445 myname=self.index[startpos+4:startpos+4+namelen] 446 a.seek(self.datapos+datapos) 447 mydata[myname] = a.read(datalen) 448 startpos=startpos+namelen+12 449 a.close() 450 return mydata
451
452 - def getboth(self):
453 """Returns an array [indexSegment,dataSegment]""" 454 if not self.scan(): 455 return None 456 457 a = open(self.file, "rb") 458 a.seek(self.datapos) 459 mydata =a.read(self.datasize) 460 a.close() 461 462 return self.index, mydata
463