github.com/xushiwei/go@v0.0.0-20130601165731-2b9d83f45bc9/src/pkg/archive/zip/struct.go (about) 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 // FileHeader describes a file within a zip file. 68 // See the zip spec for details. 69 type FileHeader struct { 70 // Name is the name of the file. 71 // It must be a relative path: it must not start with a drive 72 // letter (e.g. C:) or leading slash, and only forward slashes 73 // are allowed. 74 Name string 75 76 CreatorVersion uint16 77 ReaderVersion uint16 78 Flags uint16 79 Method uint16 80 ModifiedTime uint16 // MS-DOS time 81 ModifiedDate uint16 // MS-DOS date 82 CRC32 uint32 83 CompressedSize uint32 // deprecated; use CompressedSize64 84 UncompressedSize uint32 // deprecated; use UncompressedSize64 85 CompressedSize64 uint64 86 UncompressedSize64 uint64 87 Extra []byte 88 ExternalAttrs uint32 // Meaning depends on CreatorVersion 89 Comment string 90 } 91 92 // FileInfo returns an os.FileInfo for the FileHeader. 93 func (h *FileHeader) FileInfo() os.FileInfo { 94 return headerFileInfo{h} 95 } 96 97 // headerFileInfo implements os.FileInfo. 98 type headerFileInfo struct { 99 fh *FileHeader 100 } 101 102 func (fi headerFileInfo) Name() string { return fi.fh.Name } 103 func (fi headerFileInfo) Size() int64 { 104 if fi.fh.UncompressedSize64 > 0 { 105 return int64(fi.fh.UncompressedSize64) 106 } 107 return int64(fi.fh.UncompressedSize) 108 } 109 func (fi headerFileInfo) IsDir() bool { return fi.Mode().IsDir() } 110 func (fi headerFileInfo) ModTime() time.Time { return fi.fh.ModTime() } 111 func (fi headerFileInfo) Mode() os.FileMode { return fi.fh.Mode() } 112 func (fi headerFileInfo) Sys() interface{} { return fi.fh } 113 114 // FileInfoHeader creates a partially-populated FileHeader from an 115 // os.FileInfo. 116 func FileInfoHeader(fi os.FileInfo) (*FileHeader, error) { 117 size := fi.Size() 118 fh := &FileHeader{ 119 Name: fi.Name(), 120 UncompressedSize64: uint64(size), 121 } 122 fh.SetModTime(fi.ModTime()) 123 fh.SetMode(fi.Mode()) 124 if fh.UncompressedSize64 > uint32max { 125 fh.UncompressedSize = uint32max 126 } else { 127 fh.UncompressedSize = uint32(fh.UncompressedSize64) 128 } 129 return fh, nil 130 } 131 132 type directoryEnd struct { 133 diskNbr uint32 // unused 134 dirDiskNbr uint32 // unused 135 dirRecordsThisDisk uint64 // unused 136 directoryRecords uint64 137 directorySize uint64 138 directoryOffset uint64 // relative to file 139 commentLen uint16 140 comment string 141 } 142 143 // msDosTimeToTime converts an MS-DOS date and time into a time.Time. 144 // The resolution is 2s. 145 // See: http://msdn.microsoft.com/en-us/library/ms724247(v=VS.85).aspx 146 func msDosTimeToTime(dosDate, dosTime uint16) time.Time { 147 return time.Date( 148 // date bits 0-4: day of month; 5-8: month; 9-15: years since 1980 149 int(dosDate>>9+1980), 150 time.Month(dosDate>>5&0xf), 151 int(dosDate&0x1f), 152 153 // time bits 0-4: second/2; 5-10: minute; 11-15: hour 154 int(dosTime>>11), 155 int(dosTime>>5&0x3f), 156 int(dosTime&0x1f*2), 157 0, // nanoseconds 158 159 time.UTC, 160 ) 161 } 162 163 // timeToMsDosTime converts a time.Time to an MS-DOS date and time. 164 // The resolution is 2s. 165 // See: http://msdn.microsoft.com/en-us/library/ms724274(v=VS.85).aspx 166 func timeToMsDosTime(t time.Time) (fDate uint16, fTime uint16) { 167 t = t.In(time.UTC) 168 fDate = uint16(t.Day() + int(t.Month())<<5 + (t.Year()-1980)<<9) 169 fTime = uint16(t.Second()/2 + t.Minute()<<5 + t.Hour()<<11) 170 return 171 } 172 173 // ModTime returns the modification time. 174 // The resolution is 2s. 175 func (h *FileHeader) ModTime() time.Time { 176 return msDosTimeToTime(h.ModifiedDate, h.ModifiedTime) 177 } 178 179 // SetModTime sets the ModifiedTime and ModifiedDate fields to the given time. 180 // The resolution is 2s. 181 func (h *FileHeader) SetModTime(t time.Time) { 182 h.ModifiedDate, h.ModifiedTime = timeToMsDosTime(t) 183 } 184 185 const ( 186 // Unix constants. The specification doesn't mention them, 187 // but these seem to be the values agreed on by tools. 188 s_IFMT = 0xf000 189 s_IFSOCK = 0xc000 190 s_IFLNK = 0xa000 191 s_IFREG = 0x8000 192 s_IFBLK = 0x6000 193 s_IFDIR = 0x4000 194 s_IFCHR = 0x2000 195 s_IFIFO = 0x1000 196 s_ISUID = 0x800 197 s_ISGID = 0x400 198 s_ISVTX = 0x200 199 200 msdosDir = 0x10 201 msdosReadOnly = 0x01 202 ) 203 204 // Mode returns the permission and mode bits for the FileHeader. 205 func (h *FileHeader) Mode() (mode os.FileMode) { 206 switch h.CreatorVersion >> 8 { 207 case creatorUnix, creatorMacOSX: 208 mode = unixModeToFileMode(h.ExternalAttrs >> 16) 209 case creatorNTFS, creatorVFAT, creatorFAT: 210 mode = msdosModeToFileMode(h.ExternalAttrs) 211 } 212 if len(h.Name) > 0 && h.Name[len(h.Name)-1] == '/' { 213 mode |= os.ModeDir 214 } 215 return mode 216 } 217 218 // SetMode changes the permission and mode bits for the FileHeader. 219 func (h *FileHeader) SetMode(mode os.FileMode) { 220 h.CreatorVersion = h.CreatorVersion&0xff | creatorUnix<<8 221 h.ExternalAttrs = fileModeToUnixMode(mode) << 16 222 223 // set MSDOS attributes too, as the original zip does. 224 if mode&os.ModeDir != 0 { 225 h.ExternalAttrs |= msdosDir 226 } 227 if mode&0200 == 0 { 228 h.ExternalAttrs |= msdosReadOnly 229 } 230 } 231 232 // isZip64 returns true if the file size exceeds the 32 bit limit 233 func (fh *FileHeader) isZip64() bool { 234 return fh.CompressedSize64 > uint32max || fh.UncompressedSize64 > uint32max 235 } 236 237 func msdosModeToFileMode(m uint32) (mode os.FileMode) { 238 if m&msdosDir != 0 { 239 mode = os.ModeDir | 0777 240 } else { 241 mode = 0666 242 } 243 if m&msdosReadOnly != 0 { 244 mode &^= 0222 245 } 246 return mode 247 } 248 249 func fileModeToUnixMode(mode os.FileMode) uint32 { 250 var m uint32 251 switch mode & os.ModeType { 252 default: 253 m = s_IFREG 254 case os.ModeDir: 255 m = s_IFDIR 256 case os.ModeSymlink: 257 m = s_IFLNK 258 case os.ModeNamedPipe: 259 m = s_IFIFO 260 case os.ModeSocket: 261 m = s_IFSOCK 262 case os.ModeDevice: 263 if mode&os.ModeCharDevice != 0 { 264 m = s_IFCHR 265 } else { 266 m = s_IFBLK 267 } 268 } 269 if mode&os.ModeSetuid != 0 { 270 m |= s_ISUID 271 } 272 if mode&os.ModeSetgid != 0 { 273 m |= s_ISGID 274 } 275 if mode&os.ModeSticky != 0 { 276 m |= s_ISVTX 277 } 278 return m | uint32(mode&0777) 279 } 280 281 func unixModeToFileMode(m uint32) os.FileMode { 282 mode := os.FileMode(m & 0777) 283 switch m & s_IFMT { 284 case s_IFBLK: 285 mode |= os.ModeDevice 286 case s_IFCHR: 287 mode |= os.ModeDevice | os.ModeCharDevice 288 case s_IFDIR: 289 mode |= os.ModeDir 290 case s_IFIFO: 291 mode |= os.ModeNamedPipe 292 case s_IFLNK: 293 mode |= os.ModeSymlink 294 case s_IFREG: 295 // nothing to do 296 case s_IFSOCK: 297 mode |= os.ModeSocket 298 } 299 if m&s_ISGID != 0 { 300 mode |= os.ModeSetgid 301 } 302 if m&s_ISUID != 0 { 303 mode |= os.ModeSetuid 304 } 305 if m&s_ISVTX != 0 { 306 mode |= os.ModeSticky 307 } 308 return mode 309 }