1if not modules then modules = { } end modules [ ' util-tar ' ] = {
2 version = 1 . 001 ,
3 comment = " companion to luat-lib.mkiv " ,
4 author = " Hans Hagen, PRAGMA-ADE, Hasselt NL " ,
5 copyright = " PRAGMA ADE / ConTeXt Development Team " ,
6 license = " see context related readme files "
7}
8
9local type , tonumber = type , tonumber
10local gsub , escapedpattern = string . gsub , string . escapedpattern
11local nameonly , dirname , makedirs = file . nameonly , file . dirname , dir . makedirs
12local savedata = io . savedata
13local newreader = io . newreader
14
15local report = logs . reporter ( " tar " )
16
17local types = {
18 [ " 0 " ] = " file " ,
19 [ " \0 " ] = " regular " ,
20 [ " 1 " ] = " link " ,
21 [ " 2 " ] = " symbolic " ,
22 [ " 3 " ] = " character " ,
23 [ " 4 " ] = " block " ,
24 [ " 5 " ] = " directory " ,
25 [ " 6 " ] = " fifo " ,
26 [ " 7 " ] = " continuation " ,
27 [ " x " ] = " extended " ,
28}
29
30local function asstring ( str )
31 return str and gsub ( str , " [\0 ]+$ " , " " ) or nil
32end
33
34local function asnumber ( str )
35 str = gsub ( str , " \0$ " , " " )
36 return tonumber ( str , 8 )
37end
38
39local function opentar ( whatever , filename )
40 local f = newreader ( filename , whatever )
41 if f then
42 f . metadata = {
43 nofpaths = 0 ,
44 noffiles = 0 ,
45 noflinks = 0 ,
46 nofbytes = 0 ,
47 }
48 return f
49 end
50end
51
52local function readheader ( t )
53
54 local p = t : getposition ( )
55 local h = t : readbytetable ( 512 )
56 t : setposition ( p )
57 for i = 149 , 156 do
58 h [ i ] = 0
59 end
60 local c = 256
61 for i = 1 , 512 do
62 c = c + h [ i ]
63 end
64
65 local header = {
66 name = asstring ( t : readstring ( 100 ) ) ,
67 mode = asnumber ( t : readstring ( 8 ) ) ,
68 uid = asnumber ( t : readstring ( 8 ) ) ,
69 gid = asnumber ( t : readstring ( 8 ) ) ,
70 size = asnumber ( t : readstring ( 12 ) ) ,
71 mtime = asnumber ( t : readstring ( 12 ) ) ,
72 checksum = asnumber ( t : readstring ( 6 ) ) ,
73 dummy = t : skip ( 2 ) ,
74 typeflag = t : readstring ( 1 ) ,
75 linkname = asstring ( t : readstring ( 100 ) ) ,
76
77
78
79
80
81
82
83 padding = t : skip ( 255 ) ,
84 }
85 local typeflag = header . typeflag
86 if typeflag then
87 header . filetype = types [ typeflag ]
88 if c = = header . checksum then
89 return header
90 end
91 end
92end
93
94local readers = {
95
96 directory = function ( t , h )
97 local metadata = t . metadata
98 local filename = h . name
99 if metadata . verbose then
100 report ( " %8s %s " , " " , filename )
101 end
102 metadata . nofpaths = metadata . nofpaths + 1
103 return true
104 end ,
105
106 file = function ( t , h )
107 local metadata = t . metadata
108 local filename = h . name
109 local filesize = h . size
110 local pathname = dirname ( filename )
111 if metadata . verbose then
112 report ( " % 8i : %s " , filesize , filename )
113 end
114 if makedirs ( pathname ) then
115 savedata ( filename , t : readstring ( filesize ) )
116 else
117 t . skip ( filesize )
118 end
119 local position = t : getposition ( )
120 local target = position + ( 512 - position % 512 ) % 512
121 t : setposition ( target )
122 metadata . noffiles = metadata . noffiles + 1
123 metadata . nofbytes = metadata . nofbytes + filesize
124 return true
125 end ,
126
127 symbolic = function ( t , h )
128 local metadata = t . metadata
129 local filename = h . name
130 local linkname = h . linkname
131 if metadata . verbose then
132 report ( " %8s %s => %s " , " " , linkname , filename )
133 end
134 metadata . noflinks = metadata . noflinks + 1
135 return true
136 end ,
137
138}
139
140local skippers = {
141
142 directory = function ( t , h )
143 return true
144 end ,
145
146 file = function ( t , h )
147 local filesize = h . size
148 local fileoffset = t : getposition ( )
149 local position = filesize + fileoffset
150 local target = position + ( 512 - position % 512 ) % 512
151 t : setposition ( target )
152 return fileoffset
153 end ,
154
155 symbolic = function ( t , h )
156 return true
157 end ,
158
159}
160
161local writers = {
162
163}
164
165local function saveheader ( t , h )
166 local filetype = h . filetype
167 local reader = readers [ filetype ]
168 if reader then
169 return filetype , reader ( t , h )
170 else
171 report ( " no reader for %s " , filetype )
172 end
173end
174
175local function skipheader ( t , h )
176 local filetype = h . filetype
177 local skipper = skippers [ filetype ]
178 if skipper then
179 return filetype , skipper ( t , h )
180 else
181 report ( " no skipper for %s " , filetype )
182 end
183end
184
185local function unpacktar ( whatever , filename , verbose )
186 local t = opentar ( whatever , filename )
187 if t then
188 local metadata = t . metadata
189 statistics . starttiming ( metadata )
190 if verbose then
191 if whatever = = " string " then
192 report ( " unpacking: %i bytes " , # filename )
193 else
194 report ( " unpacking: %s " , filename )
195 end
196 report ( " " )
197 metadata . verbose = verbose
198 end
199 while true do
200 local h = readheader ( t )
201 if not h then
202 break
203 else
204 local filetype , saved = saveheader ( t , h )
205 if not saved then
206 break
207 end
208 end
209 end
210 statistics . stoptiming ( metadata )
211 metadata . runtime = statistics . elapsed ( metadata )
212 if verbose then
213 report ( " " )
214 report ( " number of paths : %i " , metadata . nofpaths )
215 report ( " number of files : %i " , metadata . noffiles )
216 report ( " number of links : %i " , metadata . noflinks )
217 report ( " number of bytes : %i " , metadata . nofbytes )
218 report ( " " )
219 report ( " runtime needed : %s " , statistics . elapsedseconds ( metadata ) )
220 report ( " " )
221 end
222 t . close ( )
223 return metadata
224 end
225end
226
227local function listtar ( whatever , filename , onlyfiles )
228 local t = opentar ( whatever , filename )
229 if t then
230 local list , n = { } , 0
231 while true do
232 local h = readheader ( t )
233 if not h then
234 break
235 else
236 local filetype , offset = skipheader ( t , h )
237 if not offset then
238 break
239 elseif filetype = = " file " then
240 n = n + 1 ; list [ n ] = { filetype , h . name , h . size }
241 elseif filetype = = " link " then
242 n = n + 1 ; list [ n ] = { filetype , h . name , h . linkfile }
243 elseif not onlyfiles then
244 n = n + 1 ; list [ n ] = { filetype , h . name }
245 end
246 end
247 end
248 t . close ( )
249
250 table . sort ( list , function ( a , b ) return a [ 2 ] < b [ 2 ] end )
251 return list
252 end
253end
254
255local function hashtar ( whatever , filename , strip )
256 local t = opentar ( whatever , filename )
257 if t then
258 local list = { }
259 if strip then
260 strip = " ^ " . . escapedpattern ( nameonly ( nameonly ( strip ) ) ) . . " / "
261 end
262 while true do
263 local h = readheader ( t )
264 if not h then
265 break
266 else
267 local filetype , offset = skipheader ( t , h )
268 if not offset then
269 break
270 else
271 local name = h . name
272 if strip then
273 name = gsub ( name , strip , " " )
274 end
275 if filetype = = " file " then
276 list [ name ] = { offset , h . size }
277 elseif filetype = = " link " then
278 list [ name ] = h . linkname
279 end
280 end
281 end
282 end
283 t . close ( )
284 return list
285 end
286end
287
288
289
290local function fetchtar ( whatever , archive , filename , list )
291 if not list then
292 list = hashtar ( whatever , archive )
293 end
294 if list then
295 local what = list [ filename ]
296 if type ( what ) = = " string " then
297 what = list [ what ]
298 end
299 if what then
300 local t = opentar ( whatever , archive )
301 if t then
302 t : setposition ( what [ 1 ] )
303 return t : readstring ( what [ 2 ] )
304 end
305 end
306 end
307end
308
309local function packtar ( whatever , filename , verbose )
310 report ( " packing will be implemented when we need it " )
311end
312
313local tar = {
314 files = {
315 unpack = function ( ... ) return unpacktar ( " file " , ... ) end ,
316 pack = function ( ... ) return packtar ( " file " , ... ) end ,
317 list = function ( ... ) return listtar ( " file " , ... ) end ,
318 hash = function ( ... ) return hashtar ( " file " , ... ) end ,
319 fetch = function ( ... ) return fetchtar ( " file " , ... ) end ,
320 } ,
321 strings = {
322 unpack = function ( ... ) return unpacktar ( " string " , ... ) end ,
323 pack = function ( ... ) return packtar ( " string " , ... ) end ,
324 list = function ( ... ) return listtar ( " string " , ... ) end ,
325 hash = function ( ... ) return hashtar ( " string " , ... ) end ,
326 fetch = function ( ... ) return fetchtar ( " string " , ... ) end ,
327 } ,
328 streams = {
329 unpack = function ( ... ) return unpacktar ( " stream " , ... ) end ,
330 pack = function ( ... ) return packtar ( " stream " , ... ) end ,
331 list = function ( ... ) return listtar ( " stream " , ... ) end ,
332 hash = function ( ... ) return hashtar ( " stream " , ... ) end ,
333 fetch = function ( ... ) return fetchtar ( " stream " , ... ) end ,
334 } ,
335}
336
337utilities . tar = tar
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359return tar
360 |