110 lines
2.9 KiB
Go
110 lines
2.9 KiB
Go
// Copyright 2010 The Go Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style
|
|
// license that can be found in the LICENSE file.
|
|
|
|
/*
|
|
Package zip provides support for reading and writing ZIP archives.
|
|
|
|
See: http://www.pkware.com/documents/casestudies/APPNOTE.TXT
|
|
|
|
This package does not support ZIP64 or disk spanning.
|
|
*/
|
|
package zip
|
|
|
|
import "errors"
|
|
import "time"
|
|
|
|
// Compression methods.
|
|
const (
|
|
Store uint16 = 0
|
|
Deflate uint16 = 8
|
|
)
|
|
|
|
const (
|
|
fileHeaderSignature = 0x04034b50
|
|
directoryHeaderSignature = 0x02014b50
|
|
directoryEndSignature = 0x06054b50
|
|
fileHeaderLen = 30 // + filename + extra
|
|
directoryHeaderLen = 46 // + filename + extra + comment
|
|
directoryEndLen = 22 // + comment
|
|
dataDescriptorLen = 12
|
|
|
|
// Constants for the first byte in CreatorVersion
|
|
creatorUnix = 3
|
|
)
|
|
|
|
type FileHeader struct {
|
|
Name string
|
|
CreatorVersion uint16
|
|
ReaderVersion uint16
|
|
Flags uint16
|
|
Method uint16
|
|
ModifiedTime uint16 // MS-DOS time
|
|
ModifiedDate uint16 // MS-DOS date
|
|
CRC32 uint32
|
|
CompressedSize uint32
|
|
UncompressedSize uint32
|
|
Extra []byte
|
|
ExternalAttrs uint32 // Meaning depends on CreatorVersion
|
|
Comment string
|
|
}
|
|
|
|
type directoryEnd struct {
|
|
diskNbr uint16 // unused
|
|
dirDiskNbr uint16 // unused
|
|
dirRecordsThisDisk uint16 // unused
|
|
directoryRecords uint16
|
|
directorySize uint32
|
|
directoryOffset uint32 // relative to file
|
|
commentLen uint16
|
|
comment string
|
|
}
|
|
|
|
func recoverError(errp *error) {
|
|
if e := recover(); e != nil {
|
|
if err, ok := e.(error); ok {
|
|
*errp = err
|
|
return
|
|
}
|
|
panic(e)
|
|
}
|
|
}
|
|
|
|
// msDosTimeToTime converts an MS-DOS date and time into a time.Time.
|
|
// The resolution is 2s.
|
|
// See: http://msdn.microsoft.com/en-us/library/ms724247(v=VS.85).aspx
|
|
func msDosTimeToTime(dosDate, dosTime uint16) time.Time {
|
|
return time.Time{
|
|
// date bits 0-4: day of month; 5-8: month; 9-15: years since 1980
|
|
Year: int64(dosDate>>9 + 1980),
|
|
Month: int(dosDate >> 5 & 0xf),
|
|
Day: int(dosDate & 0x1f),
|
|
|
|
// time bits 0-4: second/2; 5-10: minute; 11-15: hour
|
|
Hour: int(dosTime >> 11),
|
|
Minute: int(dosTime >> 5 & 0x3f),
|
|
Second: int(dosTime & 0x1f * 2),
|
|
}
|
|
}
|
|
|
|
// Mtime_ns returns the modified time in ns since epoch.
|
|
// The resolution is 2s.
|
|
func (h *FileHeader) Mtime_ns() int64 {
|
|
t := msDosTimeToTime(h.ModifiedDate, h.ModifiedTime)
|
|
return t.Seconds() * 1e9
|
|
}
|
|
|
|
// Mode returns the permission and mode bits for the FileHeader.
|
|
// An error is returned in case the information is not available.
|
|
func (h *FileHeader) Mode() (mode uint32, err error) {
|
|
if h.CreatorVersion>>8 == creatorUnix {
|
|
return h.ExternalAttrs >> 16, nil
|
|
}
|
|
return 0, errors.New("file mode not available")
|
|
}
|
|
|
|
// SetMode changes the permission and mode bits for the FileHeader.
|
|
func (h *FileHeader) SetMode(mode uint32) {
|
|
h.CreatorVersion = h.CreatorVersion&0xff | creatorUnix<<8
|
|
h.ExternalAttrs = mode << 16
|
|
}
|