diff --git a/src/swupd/files.go b/src/swupd/files.go index ba76b7b..c8d2d24 100644 --- a/src/swupd/files.go +++ b/src/swupd/files.go @@ -180,6 +180,10 @@ func (f *File) setHash(hash string) error { return nil } +func (f *File) setHashZero() { + f.Hash = 0 +} + func (f *File) getHashString() string { return *Hashes[f.Hash] } diff --git a/src/swupd/hash.go b/src/swupd/hash.go index 3677717..47553ec 100644 --- a/src/swupd/hash.go +++ b/src/swupd/hash.go @@ -2,9 +2,11 @@ package swupd type hashval int +const AllZeroHash = "0000000000000000000000000000000000000000000000000000000000000000" + // Hashes is a global map of indices to hashes -var Hashes = []*string{} -var invHash = make(map[string]hashval) +var Hashes = []*string{&AllZeroHash} +var invHash = map[string]hashval{AllZeroHash: 0} // internHash adds only new hashes to the Hashes slice and returns the index at // which they are located diff --git a/src/swupd/hash_test.go b/src/swupd/hash_test.go index 03a28be..1fde4d7 100644 --- a/src/swupd/hash_test.go +++ b/src/swupd/hash_test.go @@ -5,21 +5,27 @@ import ( "testing" ) +func resetHash() { + Hashes = []*string{&allzero} + invHash = map[string]hashval{allzero: 0} +} + func TestInternHash(t *testing.T) { // reset Hashes so we get the expected indices - Hashes = []*string{} + resetHash() testCases := []struct { hash string expected hashval }{ - {"9bcc1718757db298fb656ae6e2ee143dde746f49fbf6805db7683cb574c36728", 0}, - {"33ccead640727d66c62be03e089a3ca3f4ef7c374a3eeab79764f9509075b0d8", 1}, - {"33ccead640727d66c62be03e089a3ca3f4ef7c374a3eeab79764f9509075b0d8", 1}, - {"b26f85ffaf3595ecd9a8b1e0c894f1b9e6e3ed0e8c3f28bcde3d66e63bfedd4d", 2}, - {"a49e68b3e2230855586e9ffd1b2962a2282411a488b80e3bd65851f068394c0a", 3}, - {"a49e68b3e2230855586e9ffd1b2962a2282411a488b80e3bd65851f068394c0a", 3}, - {"a49e68b3e2230855586e9ffd1b2962a2282411a488b80e3bd65851f068394c0a", 3}, - {"864f78102661c05b61cafcb59785349fd2fb7a956ec00a77198fe5bc2432de76", 4}, + {"9bcc1718757db298fb656ae6e2ee143dde746f49fbf6805db7683cb574c36728", 1}, + {"33ccead640727d66c62be03e089a3ca3f4ef7c374a3eeab79764f9509075b0d8", 2}, + {"33ccead640727d66c62be03e089a3ca3f4ef7c374a3eeab79764f9509075b0d8", 2}, + {"b26f85ffaf3595ecd9a8b1e0c894f1b9e6e3ed0e8c3f28bcde3d66e63bfedd4d", 3}, + {"a49e68b3e2230855586e9ffd1b2962a2282411a488b80e3bd65851f068394c0a", 4}, + {"a49e68b3e2230855586e9ffd1b2962a2282411a488b80e3bd65851f068394c0a", 4}, + {"a49e68b3e2230855586e9ffd1b2962a2282411a488b80e3bd65851f068394c0a", 4}, + {"0000000000000000000000000000000000000000000000000000000000000000", 0}, + {"864f78102661c05b61cafcb59785349fd2fb7a956ec00a77198fe5bc2432de76", 5}, } for _, tc := range testCases { diff --git a/src/swupd/testhash/dohash.go b/src/swupd/testhash/dohash.go index 0d2cedf..bcdd061 100644 --- a/src/swupd/testhash/dohash.go +++ b/src/swupd/testhash/dohash.go @@ -9,8 +9,7 @@ import ( "fmt" "io/ioutil" "os" - - "golang.org/x/sys/unix" + "syscall" ) func main() { @@ -29,18 +28,30 @@ func main() { } func Hashcalc(filename string) string { - key, err := hmac_compute_key(filename) + key, ftype, err := hmac_compute_key(filename) + var result, data []byte if err != nil { fmt.Fprintf(os.Stderr, "Error stating file '%s' %v\n", filename, err) return "" } - // Only handle files for now.. - data, err := ioutil.ReadFile(filename) - if err != nil { - fmt.Fprintf(os.Stderr, "Read error for '%s' %v\n", filename, err) - return "" + switch ftype { + case '-': + data, err = ioutil.ReadFile(filename) + if err != nil { + fmt.Fprintf(os.Stderr, "Read error for '%s' %v\n", filename, err) + return "" + } + case 'd': + data = []byte("DIRECTORY") // fixed magic string + case 'l': + if target, err := os.Readlink(filename); err != nil { + fmt.Fprintf(os.Stderr, "Error readlink file '%s' %v\n", filename, err) + return "" + } else { + data = []byte(target) + } } - result := hmac_sha256_for_data(key, data) + result = hmac_sha256_for_data(key, data) return string(result[:]) } @@ -71,21 +82,36 @@ func set(out []byte, in int64) { } } -// return what should be an ascii string as an array of byte -func hmac_compute_key(filename string) ([]byte, error) { +// hmac_compute_key returns what should be an ascii string as an array of byte +// it is really ugly to be compatible with the C implementation. It is not portable +// as the C version isn't portable. +func hmac_compute_key(filename string) ([]byte, rune, error) { // Create the key updatestat := [40]byte{} - var info unix.Stat_t - if err := unix.Stat(filename, &info); err != nil { - return nil, err + var info syscall.Stat_t + if err := syscall.Lstat(filename, &info); err != nil { + return nil, 'x', err + } + ftype := '-' + // Get magic constants out of /usr/include/bits/stat.h + switch info.Mode & 0170000 { + case 0100000: // Regular file + case 0040000: // Directory + ftype = 'd' + info.Size = 0 + case 0120000: + ftype = 'l' + info.Mode = 0 + default: + return nil, 'x', fmt.Errorf("%s is not a file, directory or symlink %o", filename, info.Mode&0170000) } - set(updatestat[24:32], 0) set(updatestat[0:8], int64(info.Mode)) set(updatestat[8:16], int64(info.Uid)) set(updatestat[16:24], int64(info.Gid)) // 24:32 is rdev, but this is always zero - set(updatestat[32:40], int64(info.Size)) + set(updatestat[24:32], 0) + set(updatestat[32:40], info.Size) // fmt.Printf("key is %v\n", updatestat) key := hmac_sha256_for_data(updatestat[:], nil) - return key, nil + return key, ftype, nil }