From bfa0a3f5f18b752a6ebd3d5b37411c6871f7bb17 Mon Sep 17 00:00:00 2001 From: Runxi Yu Date: Wed, 25 Mar 2026 14:30:31 +0000 Subject: *: objectstore -> object/store --- object/store/packed/pack.go | 82 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 82 insertions(+) create mode 100644 object/store/packed/pack.go (limited to 'object/store/packed/pack.go') diff --git a/object/store/packed/pack.go b/object/store/packed/pack.go new file mode 100644 index 00000000..c384d6a5 --- /dev/null +++ b/object/store/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("objectstore/packed: pack %q too short", name) + } + + if size > int64(int(^uint(0)>>1)) { + return nil, fmt.Errorf("objectstore/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("objectstore/packed: pack %q invalid signature", name) + } + + version := binary.BigEndian.Uint32(data[4:8]) + if !packfmt.VersionSupported(version) { + _ = syscall.Munmap(data) + + return nil, fmt.Errorf("objectstore/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 +} -- cgit v1.3.1-10-gc9f91