1
2
3
4
5 package tar
6
7 import (
8 "bytes"
9 "fmt"
10 "strconv"
11 "strings"
12 "time"
13 )
14
15
16 func hasNUL(s string) bool {
17 return strings.IndexByte(s, 0) >= 0
18 }
19
20
21 func isASCII(s string) bool {
22 for _, c := range s {
23 if c >= 0x80 || c == 0x00 {
24 return false
25 }
26 }
27 return true
28 }
29
30
31
32 func toASCII(s string) string {
33 if isASCII(s) {
34 return s
35 }
36 b := make([]byte, 0, len(s))
37 for _, c := range s {
38 if c < 0x80 && c != 0x00 {
39 b = append(b, byte(c))
40 }
41 }
42 return string(b)
43 }
44
45 type parser struct {
46 err error
47 }
48
49 type formatter struct {
50 err error
51 }
52
53
54
55 func (*parser) parseString(b []byte) string {
56 if i := bytes.IndexByte(b, 0); i >= 0 {
57 return string(b[:i])
58 }
59 return string(b)
60 }
61
62
63 func (f *formatter) formatString(b []byte, s string) {
64 if len(s) > len(b) {
65 f.err = ErrFieldTooLong
66 }
67 copy(b, s)
68 if len(s) < len(b) {
69 b[len(s)] = 0
70 }
71
72
73
74
75 if len(s) > len(b) && b[len(b)-1] == '/' {
76 n := len(strings.TrimRight(s[:len(b)], "/"))
77 b[n] = 0
78 }
79 }
80
81
82
83
84
85
86
87
88 func fitsInBase256(n int, x int64) bool {
89 binBits := uint(n-1) * 8
90 return n >= 9 || (x >= -1<<binBits && x < 1<<binBits)
91 }
92
93
94
95
96 func (p *parser) parseNumeric(b []byte) int64 {
97
98
99
100 if len(b) > 0 && b[0]&0x80 != 0 {
101
102
103
104
105
106 var inv byte
107 if b[0]&0x40 != 0 {
108 inv = 0xff
109 }
110
111 var x uint64
112 for i, c := range b {
113 c ^= inv
114 if i == 0 {
115 c &= 0x7f
116 }
117 if (x >> 56) > 0 {
118 p.err = ErrHeader
119 return 0
120 }
121 x = x<<8 | uint64(c)
122 }
123 if (x >> 63) > 0 {
124 p.err = ErrHeader
125 return 0
126 }
127 if inv == 0xff {
128 return ^int64(x)
129 }
130 return int64(x)
131 }
132
133
134 return p.parseOctal(b)
135 }
136
137
138
139 func (f *formatter) formatNumeric(b []byte, x int64) {
140 if fitsInOctal(len(b), x) {
141 f.formatOctal(b, x)
142 return
143 }
144
145 if fitsInBase256(len(b), x) {
146 for i := len(b) - 1; i >= 0; i-- {
147 b[i] = byte(x)
148 x >>= 8
149 }
150 b[0] |= 0x80
151 return
152 }
153
154 f.formatOctal(b, 0)
155 f.err = ErrFieldTooLong
156 }
157
158 func (p *parser) parseOctal(b []byte) int64 {
159
160
161
162
163
164 b = bytes.Trim(b, " \x00")
165
166 if len(b) == 0 {
167 return 0
168 }
169 x, perr := strconv.ParseUint(p.parseString(b), 8, 64)
170 if perr != nil {
171 p.err = ErrHeader
172 }
173 return int64(x)
174 }
175
176 func (f *formatter) formatOctal(b []byte, x int64) {
177 if !fitsInOctal(len(b), x) {
178 x = 0
179 f.err = ErrFieldTooLong
180 }
181
182 s := strconv.FormatInt(x, 8)
183
184 if n := len(b) - len(s) - 1; n > 0 {
185 s = strings.Repeat("0", n) + s
186 }
187 f.formatString(b, s)
188 }
189
190
191
192 func fitsInOctal(n int, x int64) bool {
193 octBits := uint(n-1) * 3
194 return x >= 0 && (n >= 22 || x < 1<<octBits)
195 }
196
197
198
199
200 func parsePAXTime(s string) (time.Time, error) {
201 const maxNanoSecondDigits = 9
202
203
204 ss, sn := s, ""
205 if pos := strings.IndexByte(s, '.'); pos >= 0 {
206 ss, sn = s[:pos], s[pos+1:]
207 }
208
209
210 secs, err := strconv.ParseInt(ss, 10, 64)
211 if err != nil {
212 return time.Time{}, ErrHeader
213 }
214 if len(sn) == 0 {
215 return time.Unix(secs, 0), nil
216 }
217
218
219 if strings.Trim(sn, "0123456789") != "" {
220 return time.Time{}, ErrHeader
221 }
222 if len(sn) < maxNanoSecondDigits {
223 sn += strings.Repeat("0", maxNanoSecondDigits-len(sn))
224 } else {
225 sn = sn[:maxNanoSecondDigits]
226 }
227 nsecs, _ := strconv.ParseInt(sn, 10, 64)
228 if len(ss) > 0 && ss[0] == '-' {
229 return time.Unix(secs, -1*nsecs), nil
230 }
231 return time.Unix(secs, nsecs), nil
232 }
233
234
235
236 func formatPAXTime(ts time.Time) (s string) {
237 secs, nsecs := ts.Unix(), ts.Nanosecond()
238 if nsecs == 0 {
239 return strconv.FormatInt(secs, 10)
240 }
241
242
243 sign := ""
244 if secs < 0 {
245 sign = "-"
246 secs = -(secs + 1)
247 nsecs = -(nsecs - 1e9)
248 }
249 return strings.TrimRight(fmt.Sprintf("%s%d.%09d", sign, secs, nsecs), "0")
250 }
251
252
253
254
255 func parsePAXRecord(s string) (k, v, r string, err error) {
256
257 sp := strings.IndexByte(s, ' ')
258 if sp == -1 {
259 return "", "", s, ErrHeader
260 }
261
262
263 n, perr := strconv.ParseInt(s[:sp], 10, 0)
264 if perr != nil || n < 5 || int64(len(s)) < n {
265 return "", "", s, ErrHeader
266 }
267
268 afterSpace := int64(sp + 1)
269 beforeLastNewLine := n - 1
270
271
272
273
274
275
276
277
278
279
280
281
282
283 if afterSpace >= beforeLastNewLine {
284 return "", "", s, ErrHeader
285 }
286
287
288 rec, nl, rem := s[afterSpace:beforeLastNewLine], s[beforeLastNewLine:n], s[n:]
289 if nl != "\n" {
290 return "", "", s, ErrHeader
291 }
292
293
294 eq := strings.IndexByte(rec, '=')
295 if eq == -1 {
296 return "", "", s, ErrHeader
297 }
298 k, v = rec[:eq], rec[eq+1:]
299
300 if !validPAXRecord(k, v) {
301 return "", "", s, ErrHeader
302 }
303 return k, v, rem, nil
304 }
305
306
307
308 func formatPAXRecord(k, v string) (string, error) {
309 if !validPAXRecord(k, v) {
310 return "", ErrHeader
311 }
312
313 const padding = 3
314 size := len(k) + len(v) + padding
315 size += len(strconv.Itoa(size))
316 record := strconv.Itoa(size) + " " + k + "=" + v + "\n"
317
318
319 if len(record) != size {
320 size = len(record)
321 record = strconv.Itoa(size) + " " + k + "=" + v + "\n"
322 }
323 return record, nil
324 }
325
326
327
328
329
330
331
332
333
334
335 func validPAXRecord(k, v string) bool {
336 if k == "" || strings.IndexByte(k, '=') >= 0 {
337 return false
338 }
339 switch k {
340 case paxPath, paxLinkpath, paxUname, paxGname:
341 return !hasNUL(v)
342 default:
343 return !hasNUL(k)
344 }
345 }
346
View as plain text