...
Source file src/archive/zip/struct.go
1
2
3
4
5
20 package zip
21
22 import (
23 "os"
24 "path"
25 "time"
26 )
27
28
29 const (
30 Store uint16 = 0
31 Deflate uint16 = 8
32 )
33
34 const (
35 fileHeaderSignature = 0x04034b50
36 directoryHeaderSignature = 0x02014b50
37 directoryEndSignature = 0x06054b50
38 directory64LocSignature = 0x07064b50
39 directory64EndSignature = 0x06064b50
40 dataDescriptorSignature = 0x08074b50
41 fileHeaderLen = 30
42 directoryHeaderLen = 46
43 directoryEndLen = 22
44 dataDescriptorLen = 16
45 dataDescriptor64Len = 24
46 directory64LocLen = 20
47 directory64EndLen = 56
48
49
50 creatorFAT = 0
51 creatorUnix = 3
52 creatorNTFS = 11
53 creatorVFAT = 14
54 creatorMacOSX = 19
55
56
57 zipVersion20 = 20
58 zipVersion45 = 45
59
60
61 uint16max = (1 << 16) - 1
62 uint32max = (1 << 32) - 1
63
64
65
66
67
68
69
70
71
72
73 zip64ExtraID = 0x0001
74 ntfsExtraID = 0x000a
75 unixExtraID = 0x000d
76 extTimeExtraID = 0x5455
77 infoZipUnixExtraID = 0x5855
78 )
79
80
81
82 type FileHeader struct {
83
84
85
86
87
88
89
90
91
92
93
94
95 Name string
96
97
98 Comment string
99
100
101
102
103
104
105
106
107
108
109 NonUTF8 bool
110
111 CreatorVersion uint16
112 ReaderVersion uint16
113 Flags uint16
114
115
116 Method uint16
117
118
119
120
121
122
123
124
125
126
127 Modified time.Time
128 ModifiedTime uint16
129 ModifiedDate uint16
130
131 CRC32 uint32
132 CompressedSize uint32
133 UncompressedSize uint32
134 CompressedSize64 uint64
135 UncompressedSize64 uint64
136 Extra []byte
137 ExternalAttrs uint32
138 }
139
140
141 func (h *FileHeader) FileInfo() os.FileInfo {
142 return headerFileInfo{h}
143 }
144
145
146 type headerFileInfo struct {
147 fh *FileHeader
148 }
149
150 func (fi headerFileInfo) Name() string { return path.Base(fi.fh.Name) }
151 func (fi headerFileInfo) Size() int64 {
152 if fi.fh.UncompressedSize64 > 0 {
153 return int64(fi.fh.UncompressedSize64)
154 }
155 return int64(fi.fh.UncompressedSize)
156 }
157 func (fi headerFileInfo) IsDir() bool { return fi.Mode().IsDir() }
158 func (fi headerFileInfo) ModTime() time.Time {
159 if fi.fh.Modified.IsZero() {
160 return fi.fh.ModTime()
161 }
162 return fi.fh.Modified.UTC()
163 }
164 func (fi headerFileInfo) Mode() os.FileMode { return fi.fh.Mode() }
165 func (fi headerFileInfo) Sys() interface{} { return fi.fh }
166
167
168
169
170
171
172
173
174 func FileInfoHeader(fi os.FileInfo) (*FileHeader, error) {
175 size := fi.Size()
176 fh := &FileHeader{
177 Name: fi.Name(),
178 UncompressedSize64: uint64(size),
179 }
180 fh.SetModTime(fi.ModTime())
181 fh.SetMode(fi.Mode())
182 if fh.UncompressedSize64 > uint32max {
183 fh.UncompressedSize = uint32max
184 } else {
185 fh.UncompressedSize = uint32(fh.UncompressedSize64)
186 }
187 return fh, nil
188 }
189
190 type directoryEnd struct {
191 diskNbr uint32
192 dirDiskNbr uint32
193 dirRecordsThisDisk uint64
194 directoryRecords uint64
195 directorySize uint64
196 directoryOffset uint64
197 commentLen uint16
198 comment string
199 }
200
201
202
203 func timeZone(offset time.Duration) *time.Location {
204 const (
205 minOffset = -12 * time.Hour
206 maxOffset = +14 * time.Hour
207 offsetAlias = 15 * time.Minute
208 )
209 offset = offset.Round(offsetAlias)
210 if offset < minOffset || maxOffset < offset {
211 offset = 0
212 }
213 return time.FixedZone("", int(offset/time.Second))
214 }
215
216
217
218
219 func msDosTimeToTime(dosDate, dosTime uint16) time.Time {
220 return time.Date(
221
222 int(dosDate>>9+1980),
223 time.Month(dosDate>>5&0xf),
224 int(dosDate&0x1f),
225
226
227 int(dosTime>>11),
228 int(dosTime>>5&0x3f),
229 int(dosTime&0x1f*2),
230 0,
231
232 time.UTC,
233 )
234 }
235
236
237
238
239 func timeToMsDosTime(t time.Time) (fDate uint16, fTime uint16) {
240 fDate = uint16(t.Day() + int(t.Month())<<5 + (t.Year()-1980)<<9)
241 fTime = uint16(t.Second()/2 + t.Minute()<<5 + t.Hour()<<11)
242 return
243 }
244
245
246
247
248
249 func (h *FileHeader) ModTime() time.Time {
250 return msDosTimeToTime(h.ModifiedDate, h.ModifiedTime)
251 }
252
253
254
255
256
257 func (h *FileHeader) SetModTime(t time.Time) {
258 t = t.UTC()
259 h.Modified = t
260 h.ModifiedDate, h.ModifiedTime = timeToMsDosTime(t)
261 }
262
263 const (
264
265
266 s_IFMT = 0xf000
267 s_IFSOCK = 0xc000
268 s_IFLNK = 0xa000
269 s_IFREG = 0x8000
270 s_IFBLK = 0x6000
271 s_IFDIR = 0x4000
272 s_IFCHR = 0x2000
273 s_IFIFO = 0x1000
274 s_ISUID = 0x800
275 s_ISGID = 0x400
276 s_ISVTX = 0x200
277
278 msdosDir = 0x10
279 msdosReadOnly = 0x01
280 )
281
282
283 func (h *FileHeader) Mode() (mode os.FileMode) {
284 switch h.CreatorVersion >> 8 {
285 case creatorUnix, creatorMacOSX:
286 mode = unixModeToFileMode(h.ExternalAttrs >> 16)
287 case creatorNTFS, creatorVFAT, creatorFAT:
288 mode = msdosModeToFileMode(h.ExternalAttrs)
289 }
290 if len(h.Name) > 0 && h.Name[len(h.Name)-1] == '/' {
291 mode |= os.ModeDir
292 }
293 return mode
294 }
295
296
297 func (h *FileHeader) SetMode(mode os.FileMode) {
298 h.CreatorVersion = h.CreatorVersion&0xff | creatorUnix<<8
299 h.ExternalAttrs = fileModeToUnixMode(mode) << 16
300
301
302 if mode&os.ModeDir != 0 {
303 h.ExternalAttrs |= msdosDir
304 }
305 if mode&0200 == 0 {
306 h.ExternalAttrs |= msdosReadOnly
307 }
308 }
309
310
311 func (h *FileHeader) isZip64() bool {
312 return h.CompressedSize64 >= uint32max || h.UncompressedSize64 >= uint32max
313 }
314
315 func msdosModeToFileMode(m uint32) (mode os.FileMode) {
316 if m&msdosDir != 0 {
317 mode = os.ModeDir | 0777
318 } else {
319 mode = 0666
320 }
321 if m&msdosReadOnly != 0 {
322 mode &^= 0222
323 }
324 return mode
325 }
326
327 func fileModeToUnixMode(mode os.FileMode) uint32 {
328 var m uint32
329 switch mode & os.ModeType {
330 default:
331 m = s_IFREG
332 case os.ModeDir:
333 m = s_IFDIR
334 case os.ModeSymlink:
335 m = s_IFLNK
336 case os.ModeNamedPipe:
337 m = s_IFIFO
338 case os.ModeSocket:
339 m = s_IFSOCK
340 case os.ModeDevice:
341 if mode&os.ModeCharDevice != 0 {
342 m = s_IFCHR
343 } else {
344 m = s_IFBLK
345 }
346 }
347 if mode&os.ModeSetuid != 0 {
348 m |= s_ISUID
349 }
350 if mode&os.ModeSetgid != 0 {
351 m |= s_ISGID
352 }
353 if mode&os.ModeSticky != 0 {
354 m |= s_ISVTX
355 }
356 return m | uint32(mode&0777)
357 }
358
359 func unixModeToFileMode(m uint32) os.FileMode {
360 mode := os.FileMode(m & 0777)
361 switch m & s_IFMT {
362 case s_IFBLK:
363 mode |= os.ModeDevice
364 case s_IFCHR:
365 mode |= os.ModeDevice | os.ModeCharDevice
366 case s_IFDIR:
367 mode |= os.ModeDir
368 case s_IFIFO:
369 mode |= os.ModeNamedPipe
370 case s_IFLNK:
371 mode |= os.ModeSymlink
372 case s_IFREG:
373
374 case s_IFSOCK:
375 mode |= os.ModeSocket
376 }
377 if m&s_ISGID != 0 {
378 mode |= os.ModeSetgid
379 }
380 if m&s_ISUID != 0 {
381 mode |= os.ModeSetuid
382 }
383 if m&s_ISVTX != 0 {
384 mode |= os.ModeSticky
385 }
386 return mode
387 }
388
View as plain text