/[gentoo-src]/portage/pym/xpak.py
Gentoo

Contents of /portage/pym/xpak.py

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.15 - (show annotations) (download) (as text)
Sat Feb 26 06:35:20 2005 UTC (9 years, 6 months ago) by jstubbs
Branch: MAIN
CVS Tags: HEAD
Changes since 1.14: +2 -1 lines
File MIME type: text/x-python
Brought forward changes from portage_2_0

1 # Copyright 2001-2004 Gentoo Foundation
2 # Distributed under the terms of the GNU General Public License v2
3 # $Header: /var/cvsroot/gentoo-src/portage/pym/xpak.py,v 1.14 2004/11/15 21:42:50 carpaski Exp $
4 cvs_id_string="$Id: xpak.py,v 1.13.2.2 2005/01/16 02:35:33 carpaski Exp $"[5:-2]
5
6 # The format for a tbz2/xpak:
7 #
8 # tbz2: tar.bz2 + xpak + (xpak_offset) + "STOP"
9 # xpak: "XPAKPACK" + (index_len) + (data_len) + index + data + "XPAKSTOP"
10 # index: (pathname_len) + pathname + (data_offset) + (data_len)
11 # index entries are concatenated end-to-end.
12 # data: concatenated data chunks, end-to-end.
13 #
14 # [tarball]XPAKPACKIIIIDDDD[index][data]XPAKSTOPOOOOSTOP
15 #
16 # (integer) == encodeint(integer) ===> 4 characters (big-endian copy)
17 # '+' means concatenate the fields ===> All chunks are strings
18
19 import sys,os,string
20 from stat import *
21
22 def addtolist(mylist,curdir):
23 """(list, dir) --- Takes an array(list) and appends all files from dir down
24 the directory tree. Returns nothing. list is modified."""
25 for x in os.listdir("."):
26 if os.path.isdir(x):
27 os.chdir(x)
28 addtolist(mylist,curdir+x+"/")
29 os.chdir("..")
30 else:
31 if curdir+x not in mylist:
32 mylist.append(curdir+x)
33
34 def encodeint(myint):
35 """Takes a 4 byte integer and converts it into a string of 4 characters.
36 Returns the characters in a string."""
37 part1=chr((myint >> 24 ) & 0x000000ff)
38 part2=chr((myint >> 16 ) & 0x000000ff)
39 part3=chr((myint >> 8 ) & 0x000000ff)
40 part4=chr(myint & 0x000000ff)
41 return part1+part2+part3+part4
42
43 def decodeint(mystring):
44 """Takes a 4 byte string and converts it into a 4 byte integer.
45 Returns an integer."""
46 myint=0
47 myint=myint+ord(mystring[3])
48 myint=myint+(ord(mystring[2]) << 8)
49 myint=myint+(ord(mystring[1]) << 16)
50 myint=myint+(ord(mystring[0]) << 24)
51 return myint
52
53 def xpak(rootdir,outfile=None):
54 """(rootdir,outfile) -- creates an xpak segment of the directory 'rootdir'
55 and under the name 'outfile' if it is specified. Otherwise it returns the
56 xpak segment."""
57 try:
58 origdir=os.getcwd()
59 except SystemExit, e:
60 raise
61 except:
62 os.chdir("/")
63 origdir="/"
64 os.chdir(rootdir)
65 mylist=[]
66
67 addtolist(mylist,"")
68 mylist.sort()
69
70 #Our list index has been created
71
72 indexglob=""
73 indexpos=0
74 dataglob=""
75 datapos=0
76 for x in mylist:
77 a=open(x,"r")
78 newglob=a.read()
79 a.close()
80 mydatasize=len(newglob)
81 indexglob=indexglob+encodeint(len(x))+x+encodeint(datapos)+encodeint(mydatasize)
82 indexpos=indexpos+4+len(x)+4+4
83 dataglob=dataglob+newglob
84 datapos=datapos+mydatasize
85 os.chdir(origdir)
86 if outfile:
87 outf=open(outfile,"w")
88 outf.write("XPAKPACK"+encodeint(len(indexglob))+encodeint(len(dataglob)))
89 outf.write(indexglob)
90 outf.write(dataglob)
91 outf.write("XPAKSTOP")
92 outf.close()
93 else:
94 myret="XPAKPACK"+encodeint(len(indexglob))+encodeint(len(dataglob))
95 myret=myret+indexglob+dataglob+"XPAKSTOP"
96 return myret
97
98 def xsplit(infile):
99 """(infile) -- Splits the infile into two files.
100 'infile.index' contains the index segment.
101 'infile.dat' contails the data segment."""
102 myfile=open(infile,"r")
103 mydat=myfile.read()
104 myfile.close()
105
106 splits = xsplit_mem(mydat)
107 if not splits:
108 return
109
110 myfile=open(infile+".index","w")
111 myfile.write(splits[0])
112 myfile.close()
113 myfile=open(infile+".dat","w")
114 myfile.write(splits[1])
115 myfile.close()
116 return
117
118 def xsplit_mem(mydat):
119 if mydat[0:8]!="XPAKPACK":
120 return None
121 if mydat[-8:]!="XPAKSTOP":
122 return None
123 indexsize=decodeint(mydat[8:12])
124 datasize=decodeint(mydat[12:16])
125 return (mydat[16:indexsize+16], mydat[indexsize+16:-8])
126
127 def getindex(infile):
128 """(infile) -- grabs the index segment from the infile and returns it."""
129 myfile=open(infile,"r")
130 myheader=myfile.read(16)
131 if myheader[0:8]!="XPAKPACK":
132 myfile.close()
133 return
134 indexsize=decodeint(myheader[8:12])
135 myindex=myfile.read(indexsize)
136 myfile.close()
137 return myindex
138
139 def getboth(infile):
140 """(infile) -- grabs the index and data segments from the infile.
141 Returns an array [indexSegment,dataSegment]"""
142 myfile=open(infile,"r")
143 myheader=myfile.read(16)
144 if myheader[0:8]!="XPAKPACK":
145 myfile.close()
146 return
147 indexsize=decodeint(myheader[8:12])
148 datasize=decodeint(myheader[12:16])
149 myindex=myfile.read(indexsize)
150 mydata=myfile.read(datasize)
151 myfile.close()
152 return [myindex,mydata]
153
154 def listindex(myindex):
155 """Print to the terminal the filenames listed in the indexglob passed in."""
156 for x in getindex_mem(myindex):
157 print x
158
159 def getindex_mem(myindex):
160 """Returns the filenames listed in the indexglob passed in."""
161 myindexlen=len(myindex)
162 startpos=0
163 myret=[]
164 while ((startpos+8)<myindexlen):
165 mytestlen=decodeint(myindex[startpos:startpos+4])
166 myret=myret+[myindex[startpos+4:startpos+4+mytestlen]]
167 startpos=startpos+mytestlen+12
168 return myret
169
170 def searchindex(myindex,myitem):
171 """(index,item) -- Finds the offset and length of the file 'item' in the
172 datasegment via the index 'index' provided."""
173 mylen=len(myitem)
174 myindexlen=len(myindex)
175 startpos=0
176 while ((startpos+8)<myindexlen):
177 mytestlen=decodeint(myindex[startpos:startpos+4])
178 if mytestlen==mylen:
179 if myitem==myindex[startpos+4:startpos+4+mytestlen]:
180 #found
181 datapos=decodeint(myindex[startpos+4+mytestlen:startpos+8+mytestlen]);
182 datalen=decodeint(myindex[startpos+8+mytestlen:startpos+12+mytestlen]);
183 return [datapos,datalen]
184 startpos=startpos+mytestlen+12
185
186 def getitem(myid,myitem):
187 myindex=myid[0]
188 mydata=myid[1]
189 myloc=searchindex(myindex,myitem)
190 if not myloc:
191 return None
192 return mydata[myloc[0]:myloc[0]+myloc[1]]
193
194 def xpand(myid,mydest):
195 myindex=myid[0]
196 mydata=myid[1]
197 try:
198 origdir=os.getcwd()
199 except SystemExit, e:
200 raise
201 except:
202 os.chdir("/")
203 origdir="/"
204 os.chdir(mydest)
205 myindexlen=len(myindex)
206 startpos=0
207 while ((startpos+8)<myindexlen):
208 namelen=decodeint(myindex[startpos:startpos+4])
209 datapos=decodeint(myindex[startpos+4+namelen:startpos+8+namelen]);
210 datalen=decodeint(myindex[startpos+8+namelen:startpos+12+namelen]);
211 myname=myindex[startpos+4:startpos+4+namelen]
212 dirname=os.path.dirname(myname)
213 if dirname:
214 if not os.path.exists(dirname):
215 os.makedirs(dirname)
216 mydat=open(myname,"w")
217 mydat.write(mydata[datapos:datapos+datalen])
218 mydat.close()
219 startpos=startpos+namelen+12
220 os.chdir(origdir)
221
222 class tbz2:
223 def __init__(self,myfile):
224 self.file=myfile
225 self.filestat=None
226 self.index=""
227 self.infosize=0
228 self.xpaksize=0
229 self.indexsize=None
230 self.datasize=None
231 self.indexpos=None
232 self.datapos=None
233 self.scan()
234
235 def decompose(self,datadir,cleanup=1):
236 """Alias for unpackinfo() --- Complement to recompose() but optionally
237 deletes the destination directory. Extracts the xpak from the tbz2 into
238 the directory provided. Raises IOError if scan() fails.
239 Returns result of upackinfo()."""
240 if not self.scan():
241 raise IOError
242 if cleanup and os.path.exists(datadir):
243 # XXX: Potentially bad
244 os.system("rm -Rf "+datadir+"/*")
245 if not os.path.exists(datadir):
246 os.makedirs(datadir)
247 return self.unpackinfo(datadir)
248 def compose(self,datadir,cleanup=0):
249 """Alias for recompose()."""
250 return recompose(datadir,cleanup)
251 def recompose(self,datadir,cleanup=0):
252 """Creates an xpak segment from the datadir provided, truncates the tbz2
253 to the end of regular data if an xpak segment already exists, and adds
254 the new segment to the file with terminating info."""
255 self.scan() # Don't care about condition... We'll rewrite the data anyway.
256 myfile=open(self.file,"a+")
257 if not myfile:
258 raise IOError
259 myfile.seek(-self.xpaksize,2) # 0,2 or -0,2 just mean EOF.
260 myfile.truncate()
261 xpdata=xpak(datadir)
262 myfile.write(xpdata+encodeint(len(xpdata))+"STOP")
263 myfile.flush()
264 myfile.close()
265 if cleanup:
266 # XXX: Potentially bad
267 os.system("rm -Rf "+datadir)
268 return 1
269
270 def scan(self):
271 """Scans the tbz2 to locate the xpak segment and setup internal values.
272 This function is called by relevant functions already."""
273 try:
274 mystat=os.stat(self.file)
275 if self.filestat:
276 changed=0
277 for x in [ST_SIZE, ST_MTIME, ST_CTIME]:
278 if mystat[x] != self.filestat[x]:
279 changed=1
280 if not changed:
281 return 1
282 self.filestat=mystat
283 a=open(self.file,"r")
284 a.seek(-16,2)
285 trailer=a.read()
286 self.infosize=0
287 self.xpaksize=0
288 if trailer[-4:]!="STOP":
289 a.close()
290 return 0
291 if trailer[0:8]!="XPAKSTOP":
292 a.close()
293 return 0
294 self.infosize=decodeint(trailer[8:12])
295 self.xpaksize=self.infosize+8
296 a.seek(-(self.xpaksize),2)
297 header=a.read(16)
298 if header[0:8]!="XPAKPACK":
299 a.close()
300 return 0
301 self.indexsize=decodeint(header[8:12])
302 self.datasize=decodeint(header[12:16])
303 self.indexpos=a.tell()
304 self.index=a.read(self.indexsize)
305 self.datapos=a.tell()
306 a.close()
307 return 2
308 except SystemExit, e:
309 raise
310 except:
311 return 0
312
313 def filelist(self):
314 """Return an array of each file listed in the index."""
315 if not self.scan():
316 return None
317 return getindex_mem(self.index)
318
319 def getfile(self,myfile,mydefault=None):
320 """Finds 'myfile' in the data segment and returns it."""
321 if not self.scan():
322 return None
323 myresult=searchindex(self.index,myfile)
324 if not myresult:
325 return mydefault
326 a=open(self.file,"r")
327 a.seek(self.datapos+myresult[0],0)
328 myreturn=a.read(myresult[1])
329 a.close()
330 return myreturn
331
332 def getelements(self,myfile):
333 """A split/array representation of tbz2.getfile()"""
334 mydat=self.getfile(myfile)
335 if not mydat:
336 return []
337 return string.split(mydat)
338
339 def unpackinfo(self,mydest):
340 """Unpacks all the files from the dataSegment into 'mydest'."""
341 if not self.scan():
342 return 0
343 try:
344 origdir=os.getcwd()
345 except SystemExit, e:
346 raise
347 except:
348 os.chdir("/")
349 origdir="/"
350 a=open(self.file,"r")
351 if not os.path.exists(mydest):
352 os.makedirs(mydest)
353 os.chdir(mydest)
354 startpos=0
355 while ((startpos+8)<self.indexsize):
356 namelen=decodeint(self.index[startpos:startpos+4])
357 datapos=decodeint(self.index[startpos+4+namelen:startpos+8+namelen]);
358 datalen=decodeint(self.index[startpos+8+namelen:startpos+12+namelen]);
359 myname=self.index[startpos+4:startpos+4+namelen]
360 dirname=os.path.dirname(myname)
361 if dirname:
362 if not os.path.exists(dirname):
363 os.makedirs(dirname)
364 mydat=open(myname,"w")
365 a.seek(self.datapos+datapos)
366 mydat.write(a.read(datalen))
367 mydat.close()
368 startpos=startpos+namelen+12
369 a.close()
370 os.chdir(origdir)
371 return 1

  ViewVC Help
Powered by ViewVC 1.1.20