1 USING: combinators io io.files io.files.links io.directories
2 io.pathnames io.streams.string kernel math math.parser
3 continuations namespaces pack prettyprint sequences strings
4 system tools.hexdump io.encodings.binary summary accessors
5 io.backend byte-arrays ;
8 : zero-checksum 256 ; inline
9 : block-size 512 ; inline
11 TUPLE: tar-header name mode uid gid size mtime checksum typeflag
12 linkname magic version uname gname devmajor devminor prefix ;
13 ERROR: checksum-error ;
15 SYMBOLS: base-dir filename ;
17 : tar-trim ( seq -- newseq ) [ "\0 " member? ] trim ;
19 : read-c-string* ( n -- str/f )
20 read [ zero? ] trim-right [ f ] when-empty ;
22 : read-tar-header ( -- obj )
24 100 read-c-string* >>name
25 8 read-c-string* tar-trim oct> >>mode
26 8 read-c-string* tar-trim oct> >>uid
27 8 read-c-string* tar-trim oct> >>gid
28 12 read-c-string* tar-trim oct> >>size
29 12 read-c-string* tar-trim oct> >>mtime
30 8 read-c-string* tar-trim oct> >>checksum
32 100 read-c-string* >>linkname
35 32 read-c-string* >>uname
36 32 read-c-string* >>gname
37 8 read tar-trim oct> >>devmajor
38 8 read tar-trim oct> >>devminor
39 155 read-c-string* >>prefix ;
41 : header-checksum ( seq -- x )
42 148 cut-slice 8 tail-slice
45 : read-data-blocks ( tar-header -- )
48 over size>> dup block-size <= [
49 head-slice >byte-array write drop
52 [ block-size - ] change-size
62 : parse-tar-header ( seq -- obj )
63 [ header-checksum ] keep over zero-checksum = [
69 [ read-tar-header ] with-string-reader
70 [ checksum>> = [ checksum-error ] unless ] keep
73 ERROR: unknown-typeflag ch ;
74 M: unknown-typeflag summary ( obj -- str )
75 ch>> 1string "Unknown typeflag: " prepend ;
77 : tar-prepend-path ( path -- newpath )
78 base-dir get prepend-path ;
80 : read/write-blocks ( tar-header path -- )
81 binary [ read-data-blocks ] with-file-writer ;
84 : typeflag-0 ( header -- )
85 dup name>> tar-prepend-path read/write-blocks ;
88 : typeflag-1 ( header -- ) unknown-typeflag ;
91 : typeflag-2 ( header -- )
92 [ name>> ] [ linkname>> ] bi
93 [ make-link ] 2curry ignore-errors ;
96 : typeflag-3 ( header -- ) unknown-typeflag ;
99 : typeflag-4 ( header -- ) unknown-typeflag ;
102 : typeflag-5 ( header -- )
103 name>> tar-prepend-path make-directories ;
106 : typeflag-6 ( header -- ) unknown-typeflag ;
109 : typeflag-7 ( header -- ) unknown-typeflag ;
111 ! Global extended header
112 : typeflag-8 ( header -- ) unknown-typeflag ;
115 : typeflag-9 ( header -- ) unknown-typeflag ;
117 ! Global POSIX header
118 : typeflag-g ( header -- ) typeflag-0 ;
120 ! Extended POSIX header
121 : typeflag-x ( header -- ) unknown-typeflag ;
123 ! Solaris access control list
124 : typeflag-A ( header -- ) unknown-typeflag ;
127 : typeflag-D ( header -- ) unknown-typeflag ;
129 ! Solaris extended attribute file
130 : typeflag-E ( header -- ) unknown-typeflag ;
133 : typeflag-I ( header -- ) unknown-typeflag ;
136 : typeflag-K ( header -- ) unknown-typeflag ;
139 : typeflag-L ( header -- )
141 ! <string-writer> [ read-data-blocks ] keep
142 ! >string [ zero? ] trim-right filename set
143 ! filename get tar-prepend-path make-directories ;
145 ! Multi volume continuation entry
146 : typeflag-M ( header -- ) unknown-typeflag ;
149 : typeflag-N ( header -- ) unknown-typeflag ;
152 : typeflag-S ( header -- ) unknown-typeflag ;
155 : typeflag-V ( header -- ) unknown-typeflag ;
157 ! Vendor extended header type
158 : typeflag-X ( header -- ) unknown-typeflag ;
161 block-size read dup length 512 = [
166 { CHAR: 0 [ typeflag-0 ] }
167 ! { CHAR: 1 [ typeflag-1 ] }
168 { CHAR: 2 [ typeflag-2 ] }
169 ! { CHAR: 3 [ typeflag-3 ] }
170 ! { CHAR: 4 [ typeflag-4 ] }
171 { CHAR: 5 [ typeflag-5 ] }
172 ! { CHAR: 6 [ typeflag-6 ] }
173 ! { CHAR: 7 [ typeflag-7 ] }
174 { CHAR: g [ typeflag-g ] }
175 ! { CHAR: x [ typeflag-x ] }
176 ! { CHAR: A [ typeflag-A ] }
177 ! { CHAR: D [ typeflag-D ] }
178 ! { CHAR: E [ typeflag-E ] }
179 ! { CHAR: I [ typeflag-I ] }
180 ! { CHAR: K [ typeflag-K ] }
181 ! { CHAR: L [ typeflag-L ] }
182 ! { CHAR: M [ typeflag-M ] }
183 ! { CHAR: N [ typeflag-N ] }
184 ! { CHAR: S [ typeflag-S ] }
185 ! { CHAR: V [ typeflag-V ] }
186 ! { CHAR: X [ typeflag-X ] }
193 : parse-tar ( path -- )
194 normalize-path dup parent-directory base-dir [
195 binary [ (parse-tar) ] with-file-reader