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