From cfd79229fbc13103af6b30a45deb3397639a1b27 Mon Sep 17 00:00:00 2001 From: Dimitri Sokolyuk Date: Mon, 24 Apr 2017 23:42:59 +0200 Subject: add zsig --- zsig/testdata/isc.txt.gz.sig | Bin 0 -> 775 bytes zsig/zsig.go | 134 +++++++++++++++++++++++++++++++++++++++++++ zsig/zsig_test.go | 31 ++++++++++ 3 files changed, 165 insertions(+) create mode 100644 zsig/testdata/isc.txt.gz.sig create mode 100644 zsig/zsig.go create mode 100644 zsig/zsig_test.go (limited to 'zsig') diff --git a/zsig/testdata/isc.txt.gz.sig b/zsig/testdata/isc.txt.gz.sig new file mode 100644 index 0000000..0b2ab0e Binary files /dev/null and b/zsig/testdata/isc.txt.gz.sig differ diff --git a/zsig/zsig.go b/zsig/zsig.go new file mode 100644 index 0000000..2da9a1f --- /dev/null +++ b/zsig/zsig.go @@ -0,0 +1,134 @@ +package zsig + +import ( + "bufio" + "encoding/binary" + "errors" + "hash/crc32" + "io" + "time" +) + +var ErrHeader = errors.New("invalid header") + +const ( + gzipID1 = 0x1f + gzipID2 = 0x8b + gzipDeflate = 8 + flagText = 1 << 0 + flagHdrCrc = 1 << 1 + flagExtra = 1 << 2 + flagName = 1 << 3 + flagComment = 1 << 4 +) + +const BlockSz = 65536 + +var fake = []byte{gzipID1, gzipID2, gzipDeflate, flagComment, 0, 0, 0, 0, 0, 3} + +// Roadmap +// Parse gzip header (see rfc1952) +// range over content and calculate sha512/256 +// consider io.LimitReader ? + +type Header struct { + Comment string + Extra []byte + ModTime time.Time + Name string + OS byte +} + +type Reader struct { + Header + r io.Reader + digest uint32 // CRC32 IEEE +} + +func noEOF(err error) error { + if err == io.EOF { + return io.ErrUnexpectedEOF + } + return err +} + +var le = binary.LittleEndian + +func NewReader(r io.Reader) (*Reader, error) { + z := &Reader{r: r} + hdr, err := z.readHeader() + if err != nil { + return nil, err + } + z.Header = hdr + return z, nil +} + +func (z *Reader) readHeader() (hdr Header, err error) { + var buf [10]byte + if _, err := io.ReadFull(z.r, buf[:10]); err != nil { + return hdr, err + } + if buf[0] != gzipID1 || buf[1] != gzipID2 || buf[2] != gzipDeflate { + return hdr, ErrHeader + } + flg := buf[3] + if t := le.Uint32(buf[4:8]); t > 0 { + hdr.ModTime = time.Unix(int64(t), 0) + } + hdr.OS = buf[9] + z.digest = crc32.ChecksumIEEE(buf[:10]) + if flg&flagExtra != 0 { + if _, err = io.ReadFull(z.r, buf[:2]); err != nil { + return hdr, noEOF(err) + } + z.digest = crc32.Update(z.digest, crc32.IEEETable, buf[:2]) + data := make([]byte, le.Uint16(buf[:2])) + if _, err := io.ReadFull(z.r, data); err != nil { + return hdr, noEOF(err) + } + z.digest = crc32.Update(z.digest, crc32.IEEETable, data) + hdr.Extra = data + } + if flg&flagName != 0 { + s, err := z.readString() + if err != nil { + return hdr, err + } + hdr.Name = s + } + if flg&flagComment != 0 { + s, err := z.readString() + if err != nil { + return hdr, err + } + hdr.Comment = s + } + if flg&flagHdrCrc != 0 { + if _, err := io.ReadFull(z.r, buf[:2]); err != nil { + return hdr, noEOF(err) + } + digest := le.Uint16(buf[:2]) + if digest != uint16(z.digest) { + return hdr, ErrHeader + } + } + return hdr, nil +} + +func (z *Reader) readString() (string, error) { + r := bufio.NewReader(z.r) + s, err := r.ReadString(0) + if err != nil { + return "", err + } + if l := len(s); l > 0 && s[l-1] == 0 { + s = s[:l-1] // strip last zero + } + z.r = r // replace orginal reader + return s, nil +} + +func (z *Reader) Read(p []byte) (n int, err error) { + return z.r.Read(p) +} diff --git a/zsig/zsig_test.go b/zsig/zsig_test.go new file mode 100644 index 0000000..1fb6b06 --- /dev/null +++ b/zsig/zsig_test.go @@ -0,0 +1,31 @@ +package zsig + +import ( + "os" + "path" + "testing" +) + +func TestZsig(t *testing.T) { + testCases := []string{ + "isc.txt.gz.sig", + "go-1.8.tgz", + } + for _, tc := range testCases { + t.Run(tc, func(t *testing.T) { + fname := path.Join("testdata", tc) + fd, err := os.Open(fname) + if err != nil { + t.Fatal(err) + } + defer fd.Close() + + z, err := NewReader(fd) + if err != nil { + t.Error(err) + } + + t.Log(z.Header) + }) + } +} -- cgit v1.2.3