1 ! Copyright (C) 2009 Doug Coleman.
2 ! See http://factorcode.org/license.txt for BSD license.
3 USING: accessors byte-arrays combinators io io.backend
4 io.directories io.encodings.binary io.files io.files.links
5 io.pathnames io.streams.byte-array io.streams.string kernel
6 math math.parser namespaces sequences summary typed ;
9 CONSTANT: zero-checksum 256
10 CONSTANT: block-size 512
14 : save-link ( link -- )
17 TUPLE: tar-header name mode uid gid size mtime checksum typeflag
18 linkname magic version uname gname devmajor devminor prefix ;
20 ERROR: checksum-error header ;
22 : trim-string ( seq -- newseq ) [ "\0 " member? ] trim-tail ;
24 : read-c-string ( n -- str )
25 read [ zero? ] trim-tail "" like ;
27 : read-tar-header ( -- header )
29 100 read-c-string >>name
30 8 read-c-string trim-string oct> >>mode
31 8 read-c-string trim-string oct> >>uid
32 8 read-c-string trim-string oct> >>gid
33 12 read-c-string trim-string oct> >>size
34 12 read-c-string trim-string oct> >>mtime
35 8 read-c-string trim-string oct> >>checksum
37 100 read-c-string >>linkname
40 32 read-c-string >>uname
41 32 read-c-string >>gname
42 8 read trim-string oct> >>devmajor
43 8 read trim-string oct> >>devminor
44 155 read-c-string >>prefix ;
46 TYPED: checksum-header ( seq: byte-array -- n )
47 148 cut-slice 8 tail-slice [ 0 [ + ] reduce ] bi@ + 256 + >fixnum ;
49 : read-data-blocks ( header -- )
52 over size>> dup block-size <= [
56 [ block-size - ] change-size
64 ] if ; inline recursive
66 : parse-tar-header ( seq -- header )
67 dup checksum-header dup zero-checksum = [
74 binary [ read-tar-header ] with-byte-reader
76 ] dip = [ checksum-error ] unless
79 ERROR: unknown-typeflag ch ;
81 M: unknown-typeflag summary
82 ch>> [ "Unknown typeflag: " ] dip prefix ;
84 : read/write-blocks ( header path -- )
85 binary [ read-data-blocks ] with-file-writer ;
88 : typeflag-0 ( header -- )
89 dup name>> read/write-blocks ;
91 TUPLE: hard-link linkname name ;
92 C: <hard-link> hard-link
94 TUPLE: symbolic-link linkname name ;
95 C: <symbolic-link> symbolic-link
97 ! Hard link, don't call normalize-path
98 : typeflag-1 ( header -- )
99 [ linkname>> ] [ name>> ] bi <hard-link> save-link ;
101 ! Symlink, don't call normalize-path
102 : typeflag-2 ( header -- )
103 [ linkname>> ] [ name>> ] bi <symbolic-link> save-link ;
106 : typeflag-3 ( header -- ) unknown-typeflag ;
109 : typeflag-4 ( header -- ) unknown-typeflag ;
112 : typeflag-5 ( header -- )
113 name>> make-directories ;
116 : typeflag-6 ( header -- ) unknown-typeflag ;
119 : typeflag-7 ( header -- ) unknown-typeflag ;
121 ! Global extended header
122 : typeflag-8 ( header -- ) unknown-typeflag ;
125 : typeflag-9 ( header -- ) unknown-typeflag ;
127 ! Global POSIX header
128 : typeflag-g ( header -- )
129 ! Read something like: 52 comment=9f2a940965286754f3a34d5737c3097c05db8725
131 [ read-data-blocks ] with-string-writer drop ;
133 ! Extended POSIX header
134 : typeflag-x ( header -- ) unknown-typeflag ;
136 ! Solaris access control list
137 : typeflag-A ( header -- ) unknown-typeflag ;
140 : typeflag-D ( header -- ) unknown-typeflag ;
142 ! Solaris extended attribute file
143 : typeflag-E ( header -- ) unknown-typeflag ;
146 : typeflag-I ( header -- ) unknown-typeflag ;
149 : typeflag-K ( header -- ) unknown-typeflag ;
152 : typeflag-L ( header -- )
155 ! [ read-data-blocks ] with-string-writer
156 ! [ zero? ] trim-tail filename set
157 ! filename get make-directories ;
159 ! Multi volume continuation entry
160 : typeflag-M ( header -- ) unknown-typeflag ;
163 : typeflag-N ( header -- ) unknown-typeflag ;
166 : typeflag-S ( header -- ) unknown-typeflag ;
169 : typeflag-V ( header -- ) unknown-typeflag ;
171 ! Vendor extended header type
172 : typeflag-X ( header -- ) unknown-typeflag ;
175 block-size read dup length block-size = [
180 { CHAR: 0 [ typeflag-0 ] }
181 ! { CHAR: 1 [ typeflag-1 ] }
182 { CHAR: 2 [ typeflag-2 ] }
183 ! { CHAR: 3 [ typeflag-3 ] }
184 ! { CHAR: 4 [ typeflag-4 ] }
185 { CHAR: 5 [ typeflag-5 ] }
186 ! { CHAR: 6 [ typeflag-6 ] }
187 ! { CHAR: 7 [ typeflag-7 ] }
188 { CHAR: g [ typeflag-g ] }
189 ! { CHAR: x [ typeflag-x ] }
190 ! { CHAR: A [ typeflag-A ] }
191 ! { CHAR: D [ typeflag-D ] }
192 ! { CHAR: E [ typeflag-E ] }
193 ! { CHAR: I [ typeflag-I ] }
194 ! { CHAR: K [ typeflag-K ] }
195 { CHAR: L [ typeflag-L ] }
196 ! { CHAR: M [ typeflag-M ] }
197 ! { CHAR: N [ typeflag-N ] }
198 ! { CHAR: S [ typeflag-S ] }
199 ! { CHAR: V [ typeflag-V ] }
200 ! { CHAR: X [ typeflag-X ] }
207 GENERIC: do-link ( object -- )
210 [ linkname>> ] [ name>> ] bi make-hard-link ;
212 M: symbolic-link do-link
213 [ linkname>> ] [ name>> ] bi make-link ;
215 ! FIXME: linux tar calls unlinkat and makelinkat
218 [ name>> ?delete-file ] [ do-link ] bi
222 normalize-path dup parent-directory [
224 binary [ parse-tar ] with-file-reader