]> git.ipfire.org Git - thirdparty/gcc.git/blob - libgo/go/archive/zip/struct.go
libgo: Update to current sources.
[thirdparty/gcc.git] / libgo / go / archive / zip / struct.go
1 // Copyright 2010 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
4
5 /*
6 Package zip provides support for reading and writing ZIP archives.
7
8 See: http://www.pkware.com/documents/casestudies/APPNOTE.TXT
9
10 This package does not support disk spanning.
11
12 A note about ZIP64:
13
14 To be backwards compatible the FileHeader has both 32 and 64 bit Size
15 fields. The 64 bit fields will always contain the correct value and
16 for normal archives both fields will be the same. For files requiring
17 the ZIP64 format the 32 bit fields will be 0xffffffff and the 64 bit
18 fields must be used instead.
19 */
20 package zip
21
22 import (
23 "os"
24 "time"
25 )
26
27 // Compression methods.
28 const (
29 Store uint16 = 0
30 Deflate uint16 = 8
31 )
32
33 const (
34 fileHeaderSignature = 0x04034b50
35 directoryHeaderSignature = 0x02014b50
36 directoryEndSignature = 0x06054b50
37 directory64LocSignature = 0x07064b50
38 directory64EndSignature = 0x06064b50
39 dataDescriptorSignature = 0x08074b50 // de-facto standard; required by OS X Finder
40 fileHeaderLen = 30 // + filename + extra
41 directoryHeaderLen = 46 // + filename + extra + comment
42 directoryEndLen = 22 // + comment
43 dataDescriptorLen = 16 // four uint32: descriptor signature, crc32, compressed size, size
44 dataDescriptor64Len = 24 // descriptor with 8 byte sizes
45 directory64LocLen = 20 //
46 directory64EndLen = 56 // + extra
47
48 // Constants for the first byte in CreatorVersion
49 creatorFAT = 0
50 creatorUnix = 3
51 creatorNTFS = 11
52 creatorVFAT = 14
53 creatorMacOSX = 19
54
55 // version numbers
56 zipVersion20 = 20 // 2.0
57 zipVersion45 = 45 // 4.5 (reads and writes zip64 archives)
58
59 // limits for non zip64 files
60 uint16max = (1 << 16) - 1
61 uint32max = (1 << 32) - 1
62
63 // extra header id's
64 zip64ExtraId = 0x0001 // zip64 Extended Information Extra Field
65 )
66
67 type FileHeader struct {
68 Name string
69 CreatorVersion uint16
70 ReaderVersion uint16
71 Flags uint16
72 Method uint16
73 ModifiedTime uint16 // MS-DOS time
74 ModifiedDate uint16 // MS-DOS date
75 CRC32 uint32
76 CompressedSize uint32 // deprecated; use CompressedSize64
77 UncompressedSize uint32 // deprecated; use UncompressedSize64
78 CompressedSize64 uint64
79 UncompressedSize64 uint64
80 Extra []byte
81 ExternalAttrs uint32 // Meaning depends on CreatorVersion
82 Comment string
83 }
84
85 // FileInfo returns an os.FileInfo for the FileHeader.
86 func (h *FileHeader) FileInfo() os.FileInfo {
87 return headerFileInfo{h}
88 }
89
90 // headerFileInfo implements os.FileInfo.
91 type headerFileInfo struct {
92 fh *FileHeader
93 }
94
95 func (fi headerFileInfo) Name() string { return fi.fh.Name }
96 func (fi headerFileInfo) Size() int64 {
97 if fi.fh.UncompressedSize64 > 0 {
98 return int64(fi.fh.UncompressedSize64)
99 }
100 return int64(fi.fh.UncompressedSize)
101 }
102 func (fi headerFileInfo) IsDir() bool { return fi.Mode().IsDir() }
103 func (fi headerFileInfo) ModTime() time.Time { return fi.fh.ModTime() }
104 func (fi headerFileInfo) Mode() os.FileMode { return fi.fh.Mode() }
105 func (fi headerFileInfo) Sys() interface{} { return fi.fh }
106
107 // FileInfoHeader creates a partially-populated FileHeader from an
108 // os.FileInfo.
109 func FileInfoHeader(fi os.FileInfo) (*FileHeader, error) {
110 size := fi.Size()
111 fh := &FileHeader{
112 Name: fi.Name(),
113 UncompressedSize64: uint64(size),
114 }
115 fh.SetModTime(fi.ModTime())
116 fh.SetMode(fi.Mode())
117 if fh.UncompressedSize64 > uint32max {
118 fh.UncompressedSize = uint32max
119 } else {
120 fh.UncompressedSize = uint32(fh.UncompressedSize64)
121 }
122 return fh, nil
123 }
124
125 type directoryEnd struct {
126 diskNbr uint32 // unused
127 dirDiskNbr uint32 // unused
128 dirRecordsThisDisk uint64 // unused
129 directoryRecords uint64
130 directorySize uint64
131 directoryOffset uint64 // relative to file
132 commentLen uint16
133 comment string
134 }
135
136 // msDosTimeToTime converts an MS-DOS date and time into a time.Time.
137 // The resolution is 2s.
138 // See: http://msdn.microsoft.com/en-us/library/ms724247(v=VS.85).aspx
139 func msDosTimeToTime(dosDate, dosTime uint16) time.Time {
140 return time.Date(
141 // date bits 0-4: day of month; 5-8: month; 9-15: years since 1980
142 int(dosDate>>9+1980),
143 time.Month(dosDate>>5&0xf),
144 int(dosDate&0x1f),
145
146 // time bits 0-4: second/2; 5-10: minute; 11-15: hour
147 int(dosTime>>11),
148 int(dosTime>>5&0x3f),
149 int(dosTime&0x1f*2),
150 0, // nanoseconds
151
152 time.UTC,
153 )
154 }
155
156 // timeToMsDosTime converts a time.Time to an MS-DOS date and time.
157 // The resolution is 2s.
158 // See: http://msdn.microsoft.com/en-us/library/ms724274(v=VS.85).aspx
159 func timeToMsDosTime(t time.Time) (fDate uint16, fTime uint16) {
160 t = t.In(time.UTC)
161 fDate = uint16(t.Day() + int(t.Month())<<5 + (t.Year()-1980)<<9)
162 fTime = uint16(t.Second()/2 + t.Minute()<<5 + t.Hour()<<11)
163 return
164 }
165
166 // ModTime returns the modification time.
167 // The resolution is 2s.
168 func (h *FileHeader) ModTime() time.Time {
169 return msDosTimeToTime(h.ModifiedDate, h.ModifiedTime)
170 }
171
172 // SetModTime sets the ModifiedTime and ModifiedDate fields to the given time.
173 // The resolution is 2s.
174 func (h *FileHeader) SetModTime(t time.Time) {
175 h.ModifiedDate, h.ModifiedTime = timeToMsDosTime(t)
176 }
177
178 const (
179 // Unix constants. The specification doesn't mention them,
180 // but these seem to be the values agreed on by tools.
181 s_IFMT = 0xf000
182 s_IFSOCK = 0xc000
183 s_IFLNK = 0xa000
184 s_IFREG = 0x8000
185 s_IFBLK = 0x6000
186 s_IFDIR = 0x4000
187 s_IFCHR = 0x2000
188 s_IFIFO = 0x1000
189 s_ISUID = 0x800
190 s_ISGID = 0x400
191 s_ISVTX = 0x200
192
193 msdosDir = 0x10
194 msdosReadOnly = 0x01
195 )
196
197 // Mode returns the permission and mode bits for the FileHeader.
198 func (h *FileHeader) Mode() (mode os.FileMode) {
199 switch h.CreatorVersion >> 8 {
200 case creatorUnix, creatorMacOSX:
201 mode = unixModeToFileMode(h.ExternalAttrs >> 16)
202 case creatorNTFS, creatorVFAT, creatorFAT:
203 mode = msdosModeToFileMode(h.ExternalAttrs)
204 }
205 if len(h.Name) > 0 && h.Name[len(h.Name)-1] == '/' {
206 mode |= os.ModeDir
207 }
208 return mode
209 }
210
211 // SetMode changes the permission and mode bits for the FileHeader.
212 func (h *FileHeader) SetMode(mode os.FileMode) {
213 h.CreatorVersion = h.CreatorVersion&0xff | creatorUnix<<8
214 h.ExternalAttrs = fileModeToUnixMode(mode) << 16
215
216 // set MSDOS attributes too, as the original zip does.
217 if mode&os.ModeDir != 0 {
218 h.ExternalAttrs |= msdosDir
219 }
220 if mode&0200 == 0 {
221 h.ExternalAttrs |= msdosReadOnly
222 }
223 }
224
225 // isZip64 returns true if the file size exceeds the 32 bit limit
226 func (fh *FileHeader) isZip64() bool {
227 return fh.CompressedSize64 > uint32max || fh.UncompressedSize64 > uint32max
228 }
229
230 func msdosModeToFileMode(m uint32) (mode os.FileMode) {
231 if m&msdosDir != 0 {
232 mode = os.ModeDir | 0777
233 } else {
234 mode = 0666
235 }
236 if m&msdosReadOnly != 0 {
237 mode &^= 0222
238 }
239 return mode
240 }
241
242 func fileModeToUnixMode(mode os.FileMode) uint32 {
243 var m uint32
244 switch mode & os.ModeType {
245 default:
246 m = s_IFREG
247 case os.ModeDir:
248 m = s_IFDIR
249 case os.ModeSymlink:
250 m = s_IFLNK
251 case os.ModeNamedPipe:
252 m = s_IFIFO
253 case os.ModeSocket:
254 m = s_IFSOCK
255 case os.ModeDevice:
256 if mode&os.ModeCharDevice != 0 {
257 m = s_IFCHR
258 } else {
259 m = s_IFBLK
260 }
261 }
262 if mode&os.ModeSetuid != 0 {
263 m |= s_ISUID
264 }
265 if mode&os.ModeSetgid != 0 {
266 m |= s_ISGID
267 }
268 if mode&os.ModeSticky != 0 {
269 m |= s_ISVTX
270 }
271 return m | uint32(mode&0777)
272 }
273
274 func unixModeToFileMode(m uint32) os.FileMode {
275 mode := os.FileMode(m & 0777)
276 switch m & s_IFMT {
277 case s_IFBLK:
278 mode |= os.ModeDevice
279 case s_IFCHR:
280 mode |= os.ModeDevice | os.ModeCharDevice
281 case s_IFDIR:
282 mode |= os.ModeDir
283 case s_IFIFO:
284 mode |= os.ModeNamedPipe
285 case s_IFLNK:
286 mode |= os.ModeSymlink
287 case s_IFREG:
288 // nothing to do
289 case s_IFSOCK:
290 mode |= os.ModeSocket
291 }
292 if m&s_ISGID != 0 {
293 mode |= os.ModeSetgid
294 }
295 if m&s_ISUID != 0 {
296 mode |= os.ModeSetuid
297 }
298 if m&s_ISVTX != 0 {
299 mode |= os.ModeSticky
300 }
301 return mode
302 }