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.
6 Package zip provides support for reading and writing ZIP archives.
8 See: http://www.pkware.com/documents/casestudies/APPNOTE.TXT
10 This package does not support disk spanning.
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.
27 // Compression methods.
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
48 // Constants for the first byte in CreatorVersion
56 zipVersion20 = 20 // 2.0
57 zipVersion45 = 45 // 4.5 (reads and writes zip64 archives)
59 // limits for non zip64 files
60 uint16max = (1 << 16) - 1
61 uint32max = (1 << 32) - 1
64 zip64ExtraId = 0x0001 // zip64 Extended Information Extra Field
67 type FileHeader struct {
73 ModifiedTime uint16 // MS-DOS time
74 ModifiedDate uint16 // MS-DOS date
76 CompressedSize uint32 // deprecated; use CompressedSize64
77 UncompressedSize uint32 // deprecated; use UncompressedSize64
78 CompressedSize64 uint64
79 UncompressedSize64 uint64
81 ExternalAttrs uint32 // Meaning depends on CreatorVersion
85 // FileInfo returns an os.FileInfo for the FileHeader.
86 func (h *FileHeader) FileInfo() os.FileInfo {
87 return headerFileInfo{h}
90 // headerFileInfo implements os.FileInfo.
91 type headerFileInfo struct {
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)
100 return int64(fi.fh.UncompressedSize)
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 }
107 // FileInfoHeader creates a partially-populated FileHeader from an
109 func FileInfoHeader(fi os.FileInfo) (*FileHeader, error) {
113 UncompressedSize64: uint64(size),
115 fh.SetModTime(fi.ModTime())
116 fh.SetMode(fi.Mode())
117 if fh.UncompressedSize64 > uint32max {
118 fh.UncompressedSize = uint32max
120 fh.UncompressedSize = uint32(fh.UncompressedSize64)
125 type directoryEnd struct {
126 diskNbr uint32 // unused
127 dirDiskNbr uint32 // unused
128 dirRecordsThisDisk uint64 // unused
129 directoryRecords uint64
131 directoryOffset uint64 // relative to file
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 {
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),
146 // time bits 0-4: second/2; 5-10: minute; 11-15: hour
148 int(dosTime>>5&0x3f),
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) {
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)
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)
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)
179 // Unix constants. The specification doesn't mention them,
180 // but these seem to be the values agreed on by tools.
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)
205 if len(h.Name) > 0 && h.Name[len(h.Name)-1] == '/' {
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
216 // set MSDOS attributes too, as the original zip does.
217 if mode&os.ModeDir != 0 {
218 h.ExternalAttrs |= msdosDir
221 h.ExternalAttrs |= msdosReadOnly
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
230 func msdosModeToFileMode(m uint32) (mode os.FileMode) {
232 mode = os.ModeDir | 0777
236 if m&msdosReadOnly != 0 {
242 func fileModeToUnixMode(mode os.FileMode) uint32 {
244 switch mode & os.ModeType {
251 case os.ModeNamedPipe:
256 if mode&os.ModeCharDevice != 0 {
262 if mode&os.ModeSetuid != 0 {
265 if mode&os.ModeSetgid != 0 {
268 if mode&os.ModeSticky != 0 {
271 return m | uint32(mode&0777)
274 func unixModeToFileMode(m uint32) os.FileMode {
275 mode := os.FileMode(m & 0777)
278 mode |= os.ModeDevice
280 mode |= os.ModeDevice | os.ModeCharDevice
284 mode |= os.ModeNamedPipe
286 mode |= os.ModeSymlink
290 mode |= os.ModeSocket
293 mode |= os.ModeSetgid
296 mode |= os.ModeSetuid
299 mode |= os.ModeSticky