remove math.blas.syntax and merge parsing words into math.blas.vectors/matrices
[factor/jcg.git] / extra / tar / tar.factor
bloba4413c07b39f074f6b1114a766116af3f6c634f1
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 ;
6 IN: tar
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-tail [ f ] when-empty ;
22 : read-tar-header ( -- obj )
23     \ tar-header new
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
31     read1 >>typeflag
32     100 read-c-string* >>linkname
33     6 read >>magic
34     2 read >>version
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
43     [ sum ] bi@ + 256 + ;
45 : read-data-blocks ( tar-header -- )
46     dup size>> 0 > [
47         block-size read [
48             over size>> dup block-size <= [
49                 head-slice >byte-array write drop
50             ] [
51                 drop write
52                 [ block-size - ] change-size
53                 read-data-blocks
54             ] if
55         ] [
56             drop
57         ] if*
58     ] [
59         drop
60     ] if ;
62 : parse-tar-header ( seq -- obj )
63     [ header-checksum ] keep over zero-checksum = [
64         2drop
65         \ tar-header new
66             0 >>size
67             0 >>checksum
68     ] [
69         [ read-tar-header ] with-string-reader
70         [ checksum>> = [ checksum-error ] unless ] keep
71     ] if ;
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 ;
83 ! Normal file
84 : typeflag-0 ( header -- )
85     dup name>> tar-prepend-path read/write-blocks ;
87 ! Hard link
88 : typeflag-1 ( header -- ) unknown-typeflag ;
90 ! Symlink
91 : typeflag-2 ( header -- )
92     [ name>> ] [ linkname>> ] bi
93     [ make-link ] 2curry ignore-errors ;
95 ! character special
96 : typeflag-3 ( header -- ) unknown-typeflag ;
98 ! Block special
99 : typeflag-4 ( header -- ) unknown-typeflag ;
101 ! Directory
102 : typeflag-5 ( header -- )
103     name>> tar-prepend-path make-directories ;
105 ! FIFO
106 : typeflag-6 ( header -- ) unknown-typeflag ;
108 ! Contiguous file
109 : typeflag-7 ( header -- ) unknown-typeflag ;
111 ! Global extended header
112 : typeflag-8 ( header -- ) unknown-typeflag ;
114 ! Extended header
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 ;
126 ! GNU dumpdir
127 : typeflag-D ( header -- ) unknown-typeflag ;
129 ! Solaris extended attribute file
130 : typeflag-E ( header -- ) unknown-typeflag ;
132 ! Inode metadata
133 : typeflag-I ( header -- ) unknown-typeflag ;
135 ! Long link name
136 : typeflag-K ( header -- ) unknown-typeflag ;
138 ! Long file name
139 : typeflag-L ( header -- )
140     drop ;
141     ! <string-writer> [ read-data-blocks ] keep
142     ! >string [ zero? ] trim-tail filename set
143     ! filename get tar-prepend-path make-directories ;
145 ! Multi volume continuation entry
146 : typeflag-M ( header -- ) unknown-typeflag ;
148 ! GNU long file name
149 : typeflag-N ( header -- ) unknown-typeflag ;
151 ! Sparse file
152 : typeflag-S ( header -- ) unknown-typeflag ;
154 ! Volume header
155 : typeflag-V ( header -- ) unknown-typeflag ;
157 ! Vendor extended header type
158 : typeflag-X ( header -- ) unknown-typeflag ;
160 : (parse-tar) ( -- )
161     block-size read dup length 512 = [
162         parse-tar-header
163         dup typeflag>>
164         {
165             { 0 [ typeflag-0 ] }
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 ] }
187             { f [ drop ] }
188         } case (parse-tar)
189     ] [
190         drop
191     ] if ;
193 : parse-tar ( path -- )
194     normalize-path dup parent-directory base-dir [
195          binary [ (parse-tar) ] with-file-reader
196     ] with-variable ;