1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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
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
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
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
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
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
164 if mydat[0:8] != XPAKPACK:
165 return None
166 if mydat[-8:] != XPAKSTOP:
167 return None
168 indexsize=decodeint(mydat[8:12])
169
170 return (mydat[16:indexsize+16], mydat[indexsize+16:-8])
171
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
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
200 """Print to the terminal the filenames listed in the indexglob passed in."""
201 for x in getindex_mem(myindex):
202 print(x)
203
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
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
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
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
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
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
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):
296
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
307 self.scan()
308 myfile=open(self.file, "ab+")
309 if not myfile:
310 raise IOError
311 myfile.seek(-self.xpaksize, os.SEEK_END)
312 myfile.truncate()
313 myfile.write(xpdata+encodeint(len(xpdata))+STOP)
314 myfile.flush()
315 myfile.close()
316 return 1
317
319 datadir_split = os.path.split(datadir)
320 if len(datadir_split) >= 2 and len(datadir_split[1]) > 0:
321
322
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
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
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
394 """A split/array representation of tbz2.getfile()"""
395 mydat=self.getfile(myfile)
396 if not mydat:
397 return []
398 return mydat.split()
399
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
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
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