1
2
3
4
5 package tar
6
7 import "strings"
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46 type Format int
47
48
49 const (
50
51 _ Format = (1 << iota) / 4
52
53
54 FormatUnknown
55
56
57 formatV7
58
59
60
61
62
63
64
65
66
67
68 FormatUSTAR
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84 FormatPAX
85
86
87
88
89
90
91
92
93
94
95
96
97
98 FormatGNU
99
100
101
102
103 formatSTAR
104
105 formatMax
106 )
107
108 func (f Format) has(f2 Format) bool { return f&f2 != 0 }
109 func (f *Format) mayBe(f2 Format) { *f |= f2 }
110 func (f *Format) mayOnlyBe(f2 Format) { *f &= f2 }
111 func (f *Format) mustNotBe(f2 Format) { *f &^= f2 }
112
113 var formatNames = map[Format]string{
114 formatV7: "V7", FormatUSTAR: "USTAR", FormatPAX: "PAX", FormatGNU: "GNU", formatSTAR: "STAR",
115 }
116
117 func (f Format) String() string {
118 var ss []string
119 for f2 := Format(1); f2 < formatMax; f2 <<= 1 {
120 if f.has(f2) {
121 ss = append(ss, formatNames[f2])
122 }
123 }
124 switch len(ss) {
125 case 0:
126 return "<unknown>"
127 case 1:
128 return ss[0]
129 default:
130 return "(" + strings.Join(ss, " | ") + ")"
131 }
132 }
133
134
135 const (
136 magicGNU, versionGNU = "ustar ", " \x00"
137 magicUSTAR, versionUSTAR = "ustar\x00", "00"
138 trailerSTAR = "tar\x00"
139 )
140
141
142 const (
143 blockSize = 512
144 nameSize = 100
145 prefixSize = 155
146
147
148
149 maxSpecialFileSize = 1 << 20
150 )
151
152
153
154 func blockPadding(offset int64) (n int64) {
155 return -offset & (blockSize - 1)
156 }
157
158 var zeroBlock block
159
160 type block [blockSize]byte
161
162
163 func (b *block) toV7() *headerV7 { return (*headerV7)(b) }
164 func (b *block) toGNU() *headerGNU { return (*headerGNU)(b) }
165 func (b *block) toSTAR() *headerSTAR { return (*headerSTAR)(b) }
166 func (b *block) toUSTAR() *headerUSTAR { return (*headerUSTAR)(b) }
167 func (b *block) toSparse() sparseArray { return sparseArray(b[:]) }
168
169
170
171
172 func (b *block) getFormat() Format {
173
174 var p parser
175 value := p.parseOctal(b.toV7().chksum())
176 chksum1, chksum2 := b.computeChecksum()
177 if p.err != nil || (value != chksum1 && value != chksum2) {
178 return FormatUnknown
179 }
180
181
182 magic := string(b.toUSTAR().magic())
183 version := string(b.toUSTAR().version())
184 trailer := string(b.toSTAR().trailer())
185 switch {
186 case magic == magicUSTAR && trailer == trailerSTAR:
187 return formatSTAR
188 case magic == magicUSTAR:
189 return FormatUSTAR | FormatPAX
190 case magic == magicGNU && version == versionGNU:
191 return FormatGNU
192 default:
193 return formatV7
194 }
195 }
196
197
198
199 func (b *block) setFormat(format Format) {
200
201 switch {
202 case format.has(formatV7):
203
204 case format.has(FormatGNU):
205 copy(b.toGNU().magic(), magicGNU)
206 copy(b.toGNU().version(), versionGNU)
207 case format.has(formatSTAR):
208 copy(b.toSTAR().magic(), magicUSTAR)
209 copy(b.toSTAR().version(), versionUSTAR)
210 copy(b.toSTAR().trailer(), trailerSTAR)
211 case format.has(FormatUSTAR | FormatPAX):
212 copy(b.toUSTAR().magic(), magicUSTAR)
213 copy(b.toUSTAR().version(), versionUSTAR)
214 default:
215 panic("invalid format")
216 }
217
218
219
220 var f formatter
221 field := b.toV7().chksum()
222 chksum, _ := b.computeChecksum()
223 f.formatOctal(field[:7], chksum)
224 field[7] = ' '
225 }
226
227
228
229
230
231 func (b *block) computeChecksum() (unsigned, signed int64) {
232 for i, c := range b {
233 if 148 <= i && i < 156 {
234 c = ' '
235 }
236 unsigned += int64(c)
237 signed += int64(int8(c))
238 }
239 return unsigned, signed
240 }
241
242
243 func (b *block) reset() {
244 *b = block{}
245 }
246
247 type headerV7 [blockSize]byte
248
249 func (h *headerV7) name() []byte { return h[000:][:100] }
250 func (h *headerV7) mode() []byte { return h[100:][:8] }
251 func (h *headerV7) uid() []byte { return h[108:][:8] }
252 func (h *headerV7) gid() []byte { return h[116:][:8] }
253 func (h *headerV7) size() []byte { return h[124:][:12] }
254 func (h *headerV7) modTime() []byte { return h[136:][:12] }
255 func (h *headerV7) chksum() []byte { return h[148:][:8] }
256 func (h *headerV7) typeFlag() []byte { return h[156:][:1] }
257 func (h *headerV7) linkName() []byte { return h[157:][:100] }
258
259 type headerGNU [blockSize]byte
260
261 func (h *headerGNU) v7() *headerV7 { return (*headerV7)(h) }
262 func (h *headerGNU) magic() []byte { return h[257:][:6] }
263 func (h *headerGNU) version() []byte { return h[263:][:2] }
264 func (h *headerGNU) userName() []byte { return h[265:][:32] }
265 func (h *headerGNU) groupName() []byte { return h[297:][:32] }
266 func (h *headerGNU) devMajor() []byte { return h[329:][:8] }
267 func (h *headerGNU) devMinor() []byte { return h[337:][:8] }
268 func (h *headerGNU) accessTime() []byte { return h[345:][:12] }
269 func (h *headerGNU) changeTime() []byte { return h[357:][:12] }
270 func (h *headerGNU) sparse() sparseArray { return sparseArray(h[386:][:24*4+1]) }
271 func (h *headerGNU) realSize() []byte { return h[483:][:12] }
272
273 type headerSTAR [blockSize]byte
274
275 func (h *headerSTAR) v7() *headerV7 { return (*headerV7)(h) }
276 func (h *headerSTAR) magic() []byte { return h[257:][:6] }
277 func (h *headerSTAR) version() []byte { return h[263:][:2] }
278 func (h *headerSTAR) userName() []byte { return h[265:][:32] }
279 func (h *headerSTAR) groupName() []byte { return h[297:][:32] }
280 func (h *headerSTAR) devMajor() []byte { return h[329:][:8] }
281 func (h *headerSTAR) devMinor() []byte { return h[337:][:8] }
282 func (h *headerSTAR) prefix() []byte { return h[345:][:131] }
283 func (h *headerSTAR) accessTime() []byte { return h[476:][:12] }
284 func (h *headerSTAR) changeTime() []byte { return h[488:][:12] }
285 func (h *headerSTAR) trailer() []byte { return h[508:][:4] }
286
287 type headerUSTAR [blockSize]byte
288
289 func (h *headerUSTAR) v7() *headerV7 { return (*headerV7)(h) }
290 func (h *headerUSTAR) magic() []byte { return h[257:][:6] }
291 func (h *headerUSTAR) version() []byte { return h[263:][:2] }
292 func (h *headerUSTAR) userName() []byte { return h[265:][:32] }
293 func (h *headerUSTAR) groupName() []byte { return h[297:][:32] }
294 func (h *headerUSTAR) devMajor() []byte { return h[329:][:8] }
295 func (h *headerUSTAR) devMinor() []byte { return h[337:][:8] }
296 func (h *headerUSTAR) prefix() []byte { return h[345:][:155] }
297
298 type sparseArray []byte
299
300 func (s sparseArray) entry(i int) sparseElem { return sparseElem(s[i*24:]) }
301 func (s sparseArray) isExtended() []byte { return s[24*s.maxEntries():][:1] }
302 func (s sparseArray) maxEntries() int { return len(s) / 24 }
303
304 type sparseElem []byte
305
306 func (s sparseElem) offset() []byte { return s[00:][:12] }
307 func (s sparseElem) length() []byte { return s[12:][:12] }
308
View as plain text