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  }