This commit is contained in:
Caleb Doxsey 2025-02-10 13:04:27 -07:00
parent c8323ba744
commit 0e258a9ed4
11 changed files with 339 additions and 50 deletions

View file

@ -0,0 +1,39 @@
package fileutil
import (
"errors"
"io/fs"
"os"
"syscall"
"github.com/pomerium/pomerium/internal/hashutil"
)
// StatCheckSum returns a checksum of the file info. It is valid to run this
// function against a file path that doesn't exist and an error will not be returned.
// The file path, size, modification time, device id and inode id are used to compute
// the hash. Any change to this data, even if the underlying file contents are the
// same, will result in a new checksum, and vice-versa, if the underlying contents
// change, but none of the other data does, the checksum will be the same.
func StatCheckSum(filePath string) (uint64, error) {
d := hashutil.NewDigestWithSeed(7968108)
d.WriteStringWithLen(filePath)
for _, fn := range []func(string) (os.FileInfo, error){os.Stat, os.Lstat} {
fi, err := fn(filePath)
if errors.Is(err, fs.ErrNotExist) {
_, _ = d.Write([]byte{0})
} else if err != nil {
return 0, err
} else {
d.WriteInt64(fi.Size())
d.WriteInt64(fi.ModTime().Unix())
if s, ok := fi.Sys().(*syscall.Stat_t); ok {
d.WriteUint64(s.Dev)
d.WriteUint64(s.Ino)
}
}
}
return d.Sum64(), nil
}

View file

@ -40,6 +40,14 @@ func NewDigest() *Digest {
return &d
}
// NewDigestWithSeed creates a new digest using the given seed.
func NewDigestWithSeed(seed uint64) *Digest {
var d Digest
d.Hasher = *xxh3.NewSeed(seed)
d.Reset()
return &d
}
// WriteStringWithLen writes the string's length, then its contents to the hash.
func (d *Digest) WriteStringWithLen(s string) {
d.WriteInt32(int32(len(s)))