aboutsummaryrefslogtreecommitdiff
path: root/zsig
diff options
context:
space:
mode:
authorDimitri Sokolyuk <demon@dim13.org>2017-04-24 23:42:59 +0200
committerDimitri Sokolyuk <demon@dim13.org>2017-04-24 23:42:59 +0200
commitcfd79229fbc13103af6b30a45deb3397639a1b27 (patch)
tree4d8d61cb199469e9ffb42a02881fb0c318a93d71 /zsig
parent5ded3eaa1f1b50da4758cb1c1d9b668e4f7c1719 (diff)
add zsig
Diffstat (limited to 'zsig')
-rw-r--r--zsig/testdata/isc.txt.gz.sigbin0 -> 775 bytes
-rw-r--r--zsig/zsig.go134
-rw-r--r--zsig/zsig_test.go31
3 files changed, 165 insertions, 0 deletions
diff --git a/zsig/testdata/isc.txt.gz.sig b/zsig/testdata/isc.txt.gz.sig
new file mode 100644
index 0000000..0b2ab0e
--- /dev/null
+++ b/zsig/testdata/isc.txt.gz.sig
Binary files 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)
+ })
+ }
+}