Fast implementation of Git in pure Go
1package read
2
3import (
4 "os"
5 "syscall"
6
7 "codeberg.org/lindenii/furgit/commitgraph"
8 "codeberg.org/lindenii/furgit/internal/intconv"
9 "codeberg.org/lindenii/furgit/objectid"
10)
11
12func openLayer(root *os.Root, relPath string, algo objectid.Algorithm) (*layer, error) {
13 file, err := root.Open(relPath)
14 if err != nil {
15 return nil, err
16 }
17
18 info, err := file.Stat()
19 if err != nil {
20 _ = file.Close()
21
22 return nil, err
23 }
24
25 size := info.Size()
26 if size < int64(commitgraph.HeaderSize+commitgraph.FanoutSize+algo.Size()) {
27 _ = file.Close()
28
29 return nil, &MalformedError{Path: relPath, Reason: "file too short"}
30 }
31
32 mapLen, err := intconv.Int64ToUint64(size)
33 if err != nil {
34 _ = file.Close()
35
36 return nil, err
37 }
38
39 mapLenInt, err := intconv.Uint64ToInt(mapLen)
40 if err != nil {
41 _ = file.Close()
42
43 return nil, err
44 }
45
46 fd, err := intconv.UintptrToInt(file.Fd())
47 if err != nil {
48 _ = file.Close()
49
50 return nil, err
51 }
52
53 data, err := syscall.Mmap(fd, 0, mapLenInt, syscall.PROT_READ, syscall.MAP_PRIVATE)
54 if err != nil {
55 _ = file.Close()
56
57 return nil, err
58 }
59
60 out := &layer{
61 path: relPath,
62 file: file,
63 data: data,
64 }
65
66 parseErr := parseLayer(out, algo)
67 if parseErr != nil {
68 _ = out.close()
69
70 return nil, parseErr
71 }
72
73 verifyErr := verifyTrailerHash(out.data, algo, relPath)
74 if verifyErr != nil {
75 _ = out.close()
76
77 return nil, verifyErr
78 }
79
80 return out, nil
81}