1 USING: combinators io io.files io.streams.duplex
2 io.streams.string kernel math math.parser
3 namespaces pack prettyprint sequences strings system ;
4 USING: hexdump tools.interpreter ;
9 TUPLE: tar-header name mode uid gid size mtime checksum typeflag
10 linkname magic version uname gname devmajor devminor prefix ;
12 : <tar-header> ( -- obj ) tar-header construct-empty ;
14 : tar-trim ( seq -- newseq )
15 [ "\0 " member? ] trim ;
17 : read-tar-header ( -- obj )
19 100 read-c-string* over set-tar-header-name
20 8 read-c-string* tar-trim oct> over set-tar-header-mode
21 8 read-c-string* tar-trim oct> over set-tar-header-uid
22 8 read-c-string* tar-trim oct> over set-tar-header-gid
23 12 read-c-string* tar-trim oct> over set-tar-header-size
24 12 read-c-string* tar-trim oct> over set-tar-header-mtime
25 8 read-c-string* tar-trim oct> over set-tar-header-checksum
26 read1 over set-tar-header-typeflag
27 100 read-c-string* over set-tar-header-linkname
28 6 read over set-tar-header-magic
29 2 read over set-tar-header-version
30 32 read-c-string* over set-tar-header-uname
31 32 read-c-string* over set-tar-header-gname
32 8 read tar-trim oct> over set-tar-header-devmajor
33 8 read tar-trim oct> over set-tar-header-devminor
34 155 read-c-string* over set-tar-header-prefix ;
36 : header-checksum ( seq -- x )
37 148 swap cut-slice 8 tail-slice
38 [ 0 [ + ] reduce ] 2apply + 256 + ;
40 TUPLE: checksum-error ;
41 TUPLE: malformed-block-error ;
47 : (read-data-blocks) ( tar-header -- )
49 over tar-header-size dup 512 <= [
56 dup tar-header-size 512 - over set-tar-header-size
63 : read-data-blocks ( tar-header out -- )
64 >r stdio get r> <duplex-stream> [
68 : parse-tar-header ( seq -- obj )
69 [ header-checksum ] keep over zero-checksum = [
71 \ tar-header construct-empty
72 0 over set-tar-header-size
73 0 over set-tar-header-checksum
75 [ read-tar-header ] string-in
76 [ tar-header-checksum = [
77 \ checksum-error construct-empty throw
82 TUPLE: unknown-typeflag str ;
83 : <unknown-typeflag> ( ch -- obj )
84 1string \ unknown-typeflag construct-boa ;
86 TUPLE: unimplemented-typeflag header ;
87 : <unimplemented-typeflag> ( header -- obj )
88 global [ "Unimplemented typeflag: " print dup . flush ] bind
90 1string \ unimplemented-typeflag construct-boa ;
92 : tar-path+ ( path -- newpath )
93 base-dir get swap path+ ;
97 tar-header-name tar-path+ <file-writer>
98 [ read-data-blocks ] keep stream-close ;
101 : typeflag-1 ( header -- )
102 <unimplemented-typeflag> throw ;
105 : typeflag-2 ( header -- )
106 <unimplemented-typeflag> throw ;
109 : typeflag-3 ( header -- )
110 <unimplemented-typeflag> throw ;
113 : typeflag-4 ( header -- )
114 <unimplemented-typeflag> throw ;
117 : typeflag-5 ( header -- )
118 tar-header-name tar-path+ make-directories ;
121 : typeflag-6 ( header -- )
122 <unimplemented-typeflag> throw ;
125 : typeflag-7 ( header -- )
126 <unimplemented-typeflag> throw ;
128 ! Global extended header
129 : typeflag-8 ( header -- )
130 <unimplemented-typeflag> throw ;
133 : typeflag-9 ( header -- )
134 <unimplemented-typeflag> throw ;
136 ! Global POSIX header
137 : typeflag-g ( header -- )
138 <unimplemented-typeflag> throw ;
140 ! Extended POSIX header
141 : typeflag-x ( header -- )
142 <unimplemented-typeflag> throw ;
144 ! Solaris access control list
145 : typeflag-A ( header -- )
146 <unimplemented-typeflag> throw ;
149 : typeflag-D ( header -- )
150 <unimplemented-typeflag> throw ;
152 ! Solaris extended attribute file
153 : typeflag-E ( header -- )
154 <unimplemented-typeflag> throw ;
157 : typeflag-I ( header -- )
158 <unimplemented-typeflag> throw ;
161 : typeflag-K ( header -- )
162 <unimplemented-typeflag> throw ;
165 : typeflag-L ( header -- )
166 <string-writer> [ read-data-blocks ] keep
167 >string [ CHAR: \0 = ] rtrim filename set
168 global [ "long filename: " write filename get . flush ] bind
169 filename get tar-path+ make-directories ;
171 ! Multi volume continuation entry
172 : typeflag-M ( header -- )
173 <unimplemented-typeflag> throw ;
176 : typeflag-N ( header -- )
177 <unimplemented-typeflag> throw ;
180 : typeflag-S ( header -- )
181 <unimplemented-typeflag> throw ;
184 : typeflag-V ( header -- )
185 <unimplemented-typeflag> throw ;
187 ! Vendor extended header type
188 : typeflag-X ( header -- )
189 <unimplemented-typeflag> throw ;
193 global [ dup hexdump. flush ] bind
196 ! global [ dup tar-header-name [ print flush ] when* ] bind
197 dup tar-header-typeflag
199 { CHAR: \0 [ typeflag-0 ] }
200 { CHAR: 0 [ typeflag-0 ] }
201 { CHAR: 1 [ typeflag-1 ] }
202 { CHAR: 2 [ typeflag-2 ] }
203 { CHAR: 3 [ typeflag-3 ] }
204 { CHAR: 4 [ typeflag-4 ] }
205 { CHAR: 5 [ typeflag-5 ] }
206 { CHAR: 6 [ typeflag-6 ] }
207 { CHAR: 7 [ typeflag-7 ] }
208 { CHAR: g [ typeflag-g ] }
209 { CHAR: x [ typeflag-x ] }
210 { CHAR: A [ typeflag-A ] }
211 { CHAR: D [ typeflag-D ] }
212 { CHAR: E [ typeflag-E ] }
213 { CHAR: I [ typeflag-I ] }
214 { CHAR: K [ typeflag-K ] }
215 { CHAR: L [ typeflag-L ] }
216 { CHAR: M [ typeflag-M ] }
217 { CHAR: N [ typeflag-N ] }
218 { CHAR: S [ typeflag-S ] }
219 { CHAR: V [ typeflag-V ] }
220 { CHAR: X [ typeflag-X ] }
221 [ <unknown-typeflag> throw ]
223 ! dup tar-header-size zero? [
224 ! out-stream get [ stream-close ] when
228 ! dup tar-header-name
229 ! dup parent-dir base-dir swap path+
230 ! global [ dup [ . flush ] when* ] bind
231 ! make-directories <file-writer>
238 : parse-tar ( path -- obj )
240 "tar-test" resource-path base-dir set
241 global [ nl nl nl "Starting to parse .tar..." print flush ] bind
242 global [ "Expanding to: " write base-dir get . flush ] bind