diff options
| author | 2026-03-25 14:34:50 +0000 | |
|---|---|---|
| committer | 2026-03-25 14:34:50 +0000 | |
| commit | e4a7aa0742f5070299d37e8421c99d67f0af3f90 (patch) | |
| tree | 36d89781476a92e61280c5ff232a2773e4092c0e /object/storer/packed/pack.go | |
| parent | *: delta -> packfile/delta (diff) | |
| signature | No signature | |
*: object/store -> object/storer v0.1.107
Diffstat (limited to 'object/storer/packed/pack.go')
| -rw-r--r-- | object/storer/packed/pack.go | 82 |
1 files changed, 82 insertions, 0 deletions
diff --git a/object/storer/packed/pack.go b/object/storer/packed/pack.go new file mode 100644 index 00000000..c8135d52 --- /dev/null +++ b/object/storer/packed/pack.go @@ -0,0 +1,82 @@ +package packed + +import ( + "encoding/binary" + "fmt" + "os" + "syscall" + + "codeberg.org/lindenii/furgit/internal/intconv" + packfmt "codeberg.org/lindenii/furgit/packfile" +) + +// packFile stores one mapped and validated .pack file. +type packFile struct { + // name is the .pack basename. + name string + // file is the opened pack file descriptor. + file *os.File + // data is the mapped pack bytes. + data []byte +} + +// openPackFile maps and validates one pack file. +func openPackFile(name string, file *os.File, size int64) (*packFile, error) { + if size < 12 { + return nil, fmt.Errorf("objectstorer/packed: pack %q too short", name) + } + + if size > int64(int(^uint(0)>>1)) { + return nil, fmt.Errorf("objectstorer/packed: pack %q has unsupported size", name) + } + + fd, err := intconv.UintptrToInt(file.Fd()) + if err != nil { + return nil, err + } + + data, err := syscall.Mmap(fd, 0, int(size), syscall.PROT_READ, syscall.MAP_PRIVATE) + if err != nil { + return nil, err + } + + if binary.BigEndian.Uint32(data[:4]) != packfmt.Signature { + _ = syscall.Munmap(data) + + return nil, fmt.Errorf("objectstorer/packed: pack %q invalid signature", name) + } + + version := binary.BigEndian.Uint32(data[4:8]) + if !packfmt.VersionSupported(version) { + _ = syscall.Munmap(data) + + return nil, fmt.Errorf("objectstorer/packed: pack %q unsupported version %d", name, version) + } + + return &packFile{name: name, file: file, data: data}, nil +} + +// close unmaps and closes one pack handle. +func (pack *packFile) close() error { + var closeErr error + + if pack.data != nil { + err := syscall.Munmap(pack.data) + if err != nil && closeErr == nil { + closeErr = err + } + + pack.data = nil + } + + if pack.file != nil { + err := pack.file.Close() + if err != nil && closeErr == nil { + closeErr = err + } + + pack.file = nil + } + + return closeErr +} |
