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 ZIP64 or disk spanning.
20 // Compression methods.
27 fileHeaderSignature = 0x04034b50
28 directoryHeaderSignature = 0x02014b50
29 directoryEndSignature = 0x06054b50
30 fileHeaderLen = 30 // + filename + extra
31 directoryHeaderLen = 46 // + filename + extra + comment
32 directoryEndLen = 22 // + comment
33 dataDescriptorLen = 12
35 // Constants for the first byte in CreatorVersion
43 type FileHeader struct {
49 ModifiedTime uint16 // MS-DOS time
50 ModifiedDate uint16 // MS-DOS date
53 UncompressedSize uint32
55 ExternalAttrs uint32 // Meaning depends on CreatorVersion
59 // FileInfo returns an os.FileInfo for the FileHeader.
60 func (fh *FileHeader) FileInfo() os.FileInfo {
61 return headerFileInfo{fh}
64 // headerFileInfo implements os.FileInfo.
65 type headerFileInfo struct {
69 func (fi headerFileInfo) Name() string { return fi.fh.Name }
70 func (fi headerFileInfo) Size() int64 { return int64(fi.fh.UncompressedSize) }
71 func (fi headerFileInfo) IsDir() bool { return fi.Mode().IsDir() }
72 func (fi headerFileInfo) ModTime() time.Time { return fi.fh.ModTime() }
73 func (fi headerFileInfo) Mode() os.FileMode { return fi.fh.Mode() }
75 // FileInfoHeader creates a partially-populated FileHeader from an
77 func FileInfoHeader(fi os.FileInfo) (*FileHeader, error) {
79 if size > (1<<32 - 1) {
80 return nil, errors.New("zip: file over 4GB")
84 UncompressedSize: uint32(size),
86 fh.SetModTime(fi.ModTime())
91 type directoryEnd struct {
92 diskNbr uint16 // unused
93 dirDiskNbr uint16 // unused
94 dirRecordsThisDisk uint16 // unused
95 directoryRecords uint16
97 directoryOffset uint32 // relative to file
102 func recoverError(errp *error) {
103 if e := recover(); e != nil {
104 if err, ok := e.(error); ok {
112 // msDosTimeToTime converts an MS-DOS date and time into a time.Time.
113 // The resolution is 2s.
114 // See: http://msdn.microsoft.com/en-us/library/ms724247(v=VS.85).aspx
115 func msDosTimeToTime(dosDate, dosTime uint16) time.Time {
117 // date bits 0-4: day of month; 5-8: month; 9-15: years since 1980
118 int(dosDate>>9+1980),
119 time.Month(dosDate>>5&0xf),
122 // time bits 0-4: second/2; 5-10: minute; 11-15: hour
124 int(dosTime>>5&0x3f),
132 // timeToMsDosTime converts a time.Time to an MS-DOS date and time.
133 // The resolution is 2s.
134 // See: http://msdn.microsoft.com/en-us/library/ms724274(v=VS.85).aspx
135 func timeToMsDosTime(t time.Time) (fDate uint16, fTime uint16) {
137 fDate = uint16(t.Day() + int(t.Month())<<5 + (t.Year()-1980)<<9)
138 fTime = uint16(t.Second()/2 + t.Minute()<<5 + t.Hour()<<11)
142 // ModTime returns the modification time.
143 // The resolution is 2s.
144 func (h *FileHeader) ModTime() time.Time {
145 return msDosTimeToTime(h.ModifiedDate, h.ModifiedTime)
148 // SetModTime sets the ModifiedTime and ModifiedDate fields to the given time.
149 // The resolution is 2s.
150 func (h *FileHeader) SetModTime(t time.Time) {
151 h.ModifiedDate, h.ModifiedTime = timeToMsDosTime(t)
154 // traditional names for Unix constants
166 // Mode returns the permission and mode bits for the FileHeader.
167 func (h *FileHeader) Mode() (mode os.FileMode) {
168 switch h.CreatorVersion >> 8 {
169 case creatorUnix, creatorMacOSX:
170 mode = unixModeToFileMode(h.ExternalAttrs >> 16)
171 case creatorNTFS, creatorVFAT, creatorFAT:
172 mode = msdosModeToFileMode(h.ExternalAttrs)
174 if len(h.Name) > 0 && h.Name[len(h.Name)-1] == '/' {
180 // SetMode changes the permission and mode bits for the FileHeader.
181 func (h *FileHeader) SetMode(mode os.FileMode) {
182 h.CreatorVersion = h.CreatorVersion&0xff | creatorUnix<<8
183 h.ExternalAttrs = fileModeToUnixMode(mode) << 16
185 // set MSDOS attributes too, as the original zip does.
186 if mode&os.ModeDir != 0 {
187 h.ExternalAttrs |= msdosDir
190 h.ExternalAttrs |= msdosReadOnly
194 func msdosModeToFileMode(m uint32) (mode os.FileMode) {
196 mode = os.ModeDir | 0777
200 if m&msdosReadOnly != 0 {
206 func fileModeToUnixMode(mode os.FileMode) uint32 {
208 if mode&os.ModeDir != 0 {
213 if mode&os.ModeSetuid != 0 {
216 if mode&os.ModeSetgid != 0 {
219 return m | uint32(mode&0777)
222 func unixModeToFileMode(m uint32) os.FileMode {
224 if m&s_IFMT == s_IFDIR {
228 mode |= os.ModeSetgid
231 mode |= os.ModeSetuid
233 return mode | os.FileMode(m&0777)