aboutsummaryrefslogtreecommitdiff
path: root/object/storer/packed/pack.go
diff options
context:
space:
mode:
authorGravatar Runxi Yu2026-03-25 14:34:50 +0000
committerGravatar Runxi Yu2026-03-25 14:34:50 +0000
commite4a7aa0742f5070299d37e8421c99d67f0af3f90 (patch)
tree36d89781476a92e61280c5ff232a2773e4092c0e /object/storer/packed/pack.go
parent*: delta -> packfile/delta (diff)
signatureNo signature
*: object/store -> object/storer v0.1.107
Diffstat (limited to 'object/storer/packed/pack.go')
-rw-r--r--object/storer/packed/pack.go82
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
+}