diff options
| author | 2026-02-21 13:38:02 +0800 | |
|---|---|---|
| committer | 2026-02-21 14:28:15 +0800 | |
| commit | 94482cb2c97aa215f83940643c5d4c0933727dcb (patch) | |
| tree | bee22fa113542abd1b863ee251fdcf0f9bd409b5 /refstore | |
| parent | diff: Add package-level doc comment (diff) | |
| signature | No signature | |
*: Modernize and lint; add CI v0.1.17
Diffstat (limited to 'refstore')
| -rw-r--r-- | refstore/loose/loose_test.go | 15 | ||||
| -rw-r--r-- | refstore/packed/packed_test.go | 12 | ||||
| -rw-r--r-- | refstore/refstore.go | 2 | ||||
| -rw-r--r-- | refstore/reftable/lookup.go | 46 | ||||
| -rw-r--r-- | refstore/reftable/reftable_test.go | 15 | ||||
| -rw-r--r-- | refstore/reftable/table.go | 31 | ||||
| -rw-r--r-- | refstore/shorten_test.go | 5 |
7 files changed, 94 insertions, 32 deletions
diff --git a/refstore/loose/loose_test.go b/refstore/loose/loose_test.go index 935b4120..37f31222 100644 --- a/refstore/loose/loose_test.go +++ b/refstore/loose/loose_test.go @@ -30,7 +30,8 @@ func openLooseStore(t *testing.T, repoPath string, algo objectid.Algorithm) *loo } func TestLooseResolveAndResolveFully(t *testing.T) { - testgit.ForEachAlgorithm(t, func(t *testing.T, algo objectid.Algorithm) { + t.Parallel() + testgit.ForEachAlgorithm(t, func(t *testing.T, algo objectid.Algorithm) { //nolint:thelper testRepo := testgit.NewRepo(t, testgit.RepoOptions{ObjectFormat: algo, Bare: true}) _, _, commitID := testRepo.MakeCommit(t, "loose refs commit") testRepo.UpdateRef(t, "refs/heads/main", commitID) @@ -77,7 +78,8 @@ func TestLooseResolveAndResolveFully(t *testing.T) { } func TestLooseResolveFullyCycle(t *testing.T) { - testgit.ForEachAlgorithm(t, func(t *testing.T, algo objectid.Algorithm) { + t.Parallel() + testgit.ForEachAlgorithm(t, func(t *testing.T, algo objectid.Algorithm) { //nolint:thelper testRepo := testgit.NewRepo(t, testgit.RepoOptions{ObjectFormat: algo, Bare: true}) testRepo.SymbolicRef(t, "refs/heads/a", "refs/heads/b") testRepo.SymbolicRef(t, "refs/heads/b", "refs/heads/a") @@ -90,7 +92,8 @@ func TestLooseResolveFullyCycle(t *testing.T) { } func TestLooseListPattern(t *testing.T) { - testgit.ForEachAlgorithm(t, func(t *testing.T, algo objectid.Algorithm) { + t.Parallel() + testgit.ForEachAlgorithm(t, func(t *testing.T, algo objectid.Algorithm) { //nolint:thelper testRepo := testgit.NewRepo(t, testgit.RepoOptions{ObjectFormat: algo, Bare: true}) _, _, commitID := testRepo.MakeCommit(t, "list refs commit") testRepo.UpdateRef(t, "refs/heads/main", commitID) @@ -131,7 +134,8 @@ func TestLooseListPattern(t *testing.T) { } func TestLooseMalformedDetachedRef(t *testing.T) { - testgit.ForEachAlgorithm(t, func(t *testing.T, algo objectid.Algorithm) { + t.Parallel() + testgit.ForEachAlgorithm(t, func(t *testing.T, algo objectid.Algorithm) { //nolint:thelper testRepo := testgit.NewRepo(t, testgit.RepoOptions{ObjectFormat: algo, Bare: true}) refPath := filepath.Join(testRepo.Dir(), "refs", "heads", "bad") if err := os.MkdirAll(filepath.Dir(refPath), 0o755); err != nil { @@ -149,7 +153,8 @@ func TestLooseMalformedDetachedRef(t *testing.T) { } func TestLooseShorten(t *testing.T) { - testgit.ForEachAlgorithm(t, func(t *testing.T, algo objectid.Algorithm) { + t.Parallel() + testgit.ForEachAlgorithm(t, func(t *testing.T, algo objectid.Algorithm) { //nolint:thelper testRepo := testgit.NewRepo(t, testgit.RepoOptions{ObjectFormat: algo, Bare: true}) _, _, commitID := testRepo.MakeCommit(t, "shorten refs commit") testRepo.UpdateRef(t, "refs/heads/main", commitID) diff --git a/refstore/packed/packed_test.go b/refstore/packed/packed_test.go index c8f7f99c..efec6ca7 100644 --- a/refstore/packed/packed_test.go +++ b/refstore/packed/packed_test.go @@ -17,7 +17,7 @@ import ( func openPackedRefStoreFromRepo(t *testing.T, repoPath string, algo objectid.Algorithm) *packed.Store { t.Helper() - file, err := os.Open(filepath.Join(repoPath, "packed-refs")) + file, err := os.Open(filepath.Join(repoPath, "packed-refs")) //#nosec G304 if err != nil { t.Fatalf("open packed-refs: %v", err) } @@ -31,7 +31,8 @@ func openPackedRefStoreFromRepo(t *testing.T, repoPath string, algo objectid.Alg } func TestPackedResolveAndPeeled(t *testing.T) { - testgit.ForEachAlgorithm(t, func(t *testing.T, algo objectid.Algorithm) { + t.Parallel() + testgit.ForEachAlgorithm(t, func(t *testing.T, algo objectid.Algorithm) { //nolint:thelper testRepo := testgit.NewRepo(t, testgit.RepoOptions{ObjectFormat: algo, Bare: true}) _, _, commitID := testRepo.MakeCommit(t, "packed refs commit") testRepo.UpdateRef(t, "refs/heads/main", commitID) @@ -85,7 +86,8 @@ func TestPackedResolveAndPeeled(t *testing.T) { } func TestPackedListAndShorten(t *testing.T) { - testgit.ForEachAlgorithm(t, func(t *testing.T, algo objectid.Algorithm) { + t.Parallel() + testgit.ForEachAlgorithm(t, func(t *testing.T, algo objectid.Algorithm) { //nolint:thelper testRepo := testgit.NewRepo(t, testgit.RepoOptions{ObjectFormat: algo, Bare: true}) _, _, commitID := testRepo.MakeCommit(t, "packed refs list commit") testRepo.UpdateRef(t, "refs/heads/main", commitID) @@ -132,7 +134,8 @@ func TestPackedListAndShorten(t *testing.T) { } func TestPackedParseErrors(t *testing.T) { - testgit.ForEachAlgorithm(t, func(t *testing.T, algo objectid.Algorithm) { + t.Parallel() + testgit.ForEachAlgorithm(t, func(t *testing.T, algo objectid.Algorithm) { //nolint:thelper cases := []struct { name string data string @@ -163,6 +166,7 @@ func TestPackedParseErrors(t *testing.T) { } func TestPackedNewValidation(t *testing.T) { + t.Parallel() if _, err := packed.New(bytes.NewReader(nil), objectid.AlgorithmUnknown); !errors.Is(err, objectid.ErrInvalidAlgorithm) { t.Fatalf("packed.New invalid algorithm error = %v", err) } diff --git a/refstore/refstore.go b/refstore/refstore.go index 4cca8544..ba9141b9 100644 --- a/refstore/refstore.go +++ b/refstore/refstore.go @@ -8,7 +8,7 @@ import ( ) // ErrReferenceNotFound indicates that a reference does not exist in a backend. -// TODO: interface error? just like object not found in objectstore +// TODO: Interface error? Just like object not found in objectstore. var ErrReferenceNotFound = errors.New("refstore: reference not found") // Store reads Git references. diff --git a/refstore/reftable/lookup.go b/refstore/reftable/lookup.go index 24f9adb5..724a3727 100644 --- a/refstore/reftable/lookup.go +++ b/refstore/reftable/lookup.go @@ -5,13 +5,18 @@ import ( "fmt" "strings" + "codeberg.org/lindenii/furgit/internal/intconv" "codeberg.org/lindenii/furgit/objectid" ) // resolveRecord resolves one ref name inside a single table file. func (table *tableFile) resolveRecord(name string) (recordValue, bool, error) { if table.refIndexPos != 0 { - pos, ok, err := table.resolveRefBlockPosFromIndex(name, int(table.refIndexPos)) + indexPos, err := intconv.Uint64ToInt(table.refIndexPos) + if err != nil { + return recordValue{}, false, err + } + pos, ok, err := table.resolveRefBlockPosFromIndex(name, indexPos) if err != nil { return recordValue{}, false, err } @@ -204,10 +209,11 @@ func lookupChildPosInIndexBlock(block blockView, key string) (int, bool, error) return 0, false, err } if strings.Compare(key, name) <= 0 { - if childPos > uint64(int(^uint(0)>>1)) { - return 0, false, fmt.Errorf("index child position overflows int") + childPosInt, err := intconv.Uint64ToInt(childPos) + if err != nil { + return 0, false, fmt.Errorf("index child position conversion: %w", err) } - return int(childPos), true, nil + return childPosInt, true, nil } prev = name off = nextOff @@ -309,7 +315,7 @@ func parseBlockLayout(block blockView) (recordsStart int, recordsEnd int, restar if restartsStart < 4 { return 0, 0, nil, fmt.Errorf("invalid restart table") } - for i := 0; i < restartCount; i++ { + for i := range restartCount { off := restartsStart + i*3 rel := int(readUint24(block.payload[off : off+3])) base := block.start @@ -357,14 +363,18 @@ func parseKeyedRecord(buf []byte, off, end int, prev string) (name string, rawTy if err != nil { return "", 0, 0, err } - suffixLen := int(suffixAndType >> 3) - if suffixLen < 0 || next+suffixLen > end { + suffixLen, err := intconv.Uint64ToInt(suffixAndType >> 3) + if err != nil || suffixLen < 0 || next+suffixLen > end { return "", 0, 0, fmt.Errorf("invalid suffix length") } - if int(prefixLen) > len(prev) { + prefixLenInt, err := intconv.Uint64ToInt(prefixLen) + if err != nil { + return "", 0, 0, fmt.Errorf("invalid prefix length") + } + if prefixLenInt > len(prev) { return "", 0, 0, fmt.Errorf("invalid prefix length") } - name = prev[:prefixLen] + string(buf[next:next+suffixLen]) + name = prev[:prefixLenInt] + string(buf[next:next+suffixLen]) next += suffixLen if prev != "" && strings.Compare(name, prev) <= 0 { return "", 0, 0, fmt.Errorf("keys not strictly increasing") @@ -399,11 +409,23 @@ func parseRefValue(buf []byte, off, end int, algo objectid.Algorithm, valueType if err != nil { return recordValue{}, 0, err } - if targetLen > uint64(end-next) { + remaining := end - next + if remaining < 0 { + return recordValue{}, 0, fmt.Errorf("invalid symref target length") + } + remainingU64, err := intconv.IntToUint64(remaining) + if err != nil { + return recordValue{}, 0, fmt.Errorf("invalid symref target length") + } + if targetLen > remainingU64 { + return recordValue{}, 0, fmt.Errorf("invalid symref target length") + } + targetLenInt, err := intconv.Uint64ToInt(targetLen) + if err != nil { return recordValue{}, 0, fmt.Errorf("invalid symref target length") } - target := string(buf[next : next+int(targetLen)]) - next += int(targetLen) + target := string(buf[next : next+targetLenInt]) + next += targetLenInt return recordValue{symbolicTarget: target}, next, nil default: return recordValue{}, 0, fmt.Errorf("unsupported ref value type %d", valueType) diff --git a/refstore/reftable/reftable_test.go b/refstore/reftable/reftable_test.go index d6345f14..2a6e0738 100644 --- a/refstore/reftable/reftable_test.go +++ b/refstore/reftable/reftable_test.go @@ -40,7 +40,8 @@ func openStore(tb testing.TB, repoDir string, algo objectid.Algorithm) *reftable } func TestResolveAndResolveFully(t *testing.T) { - testgit.ForEachAlgorithm(t, func(t *testing.T, algo objectid.Algorithm) { + t.Parallel() + testgit.ForEachAlgorithm(t, func(t *testing.T, algo objectid.Algorithm) { //nolint:thelper repo := newBareReftableRepo(t, algo) _, _, id := repo.MakeCommit(t, "resolve") repo.UpdateRef(t, "refs/heads/main", id) @@ -74,7 +75,8 @@ func TestResolveAndResolveFully(t *testing.T) { } func TestResolveFullyCycle(t *testing.T) { - testgit.ForEachAlgorithm(t, func(t *testing.T, algo objectid.Algorithm) { + t.Parallel() + testgit.ForEachAlgorithm(t, func(t *testing.T, algo objectid.Algorithm) { //nolint:thelper repo := newBareReftableRepo(t, algo) repo.SymbolicRef(t, "refs/heads/a", "refs/heads/b") repo.SymbolicRef(t, "refs/heads/b", "refs/heads/a") @@ -87,7 +89,8 @@ func TestResolveFullyCycle(t *testing.T) { } func TestListAndShorten(t *testing.T) { - testgit.ForEachAlgorithm(t, func(t *testing.T, algo objectid.Algorithm) { + t.Parallel() + testgit.ForEachAlgorithm(t, func(t *testing.T, algo objectid.Algorithm) { //nolint:thelper repo := newBareReftableRepo(t, algo) _, _, id := repo.MakeCommit(t, "list") repo.UpdateRef(t, "refs/heads/main", id) @@ -133,7 +136,8 @@ func TestListAndShorten(t *testing.T) { } func TestTombstoneNewestWins(t *testing.T) { - testgit.ForEachAlgorithm(t, func(t *testing.T, algo objectid.Algorithm) { + t.Parallel() + testgit.ForEachAlgorithm(t, func(t *testing.T, algo objectid.Algorithm) { //nolint:thelper repo := newBareReftableRepo(t, algo) _, _, oldID := repo.MakeCommit(t, "old") repo.UpdateRef(t, "refs/heads/main", oldID) @@ -149,7 +153,8 @@ func TestTombstoneNewestWins(t *testing.T) { } func TestAnnotatedTagPeeled(t *testing.T) { - testgit.ForEachAlgorithm(t, func(t *testing.T, algo objectid.Algorithm) { + t.Parallel() + testgit.ForEachAlgorithm(t, func(t *testing.T, algo objectid.Algorithm) { //nolint:thelper repo := newBareReftableRepo(t, algo) _, _, commitID := repo.MakeCommit(t, "tagged") tagID := repo.TagAnnotated(t, "v1.0.0", commitID, "annotated") diff --git a/refstore/reftable/table.go b/refstore/reftable/table.go index bbef1957..35982bf9 100644 --- a/refstore/reftable/table.go +++ b/refstore/reftable/table.go @@ -8,6 +8,7 @@ import ( "os" "syscall" + "codeberg.org/lindenii/furgit/internal/intconv" "codeberg.org/lindenii/furgit/objectid" "codeberg.org/lindenii/furgit/ref" ) @@ -80,7 +81,12 @@ func openTableFile(root *os.Root, name string, algo objectid.Algorithm) (*tableF _ = file.Close() return nil, fmt.Errorf("refstore/reftable: table %q has unsupported size", name) } - data, err := syscall.Mmap(int(file.Fd()), 0, int(size), syscall.PROT_READ, syscall.MAP_PRIVATE) + fd, err := intconv.UintptrToInt(file.Fd()) + if err != nil { + _ = file.Close() + return nil, err + } + data, err := syscall.Mmap(fd, 0, int(size), syscall.PROT_READ, syscall.MAP_PRIVATE) if err != nil { _ = file.Close() return nil, err @@ -178,7 +184,10 @@ func (table *tableFile) parseMeta() error { _ = objIndexPos _ = logIndexPos - refEnd := uint64(footerStart) + refEnd, err := intconv.IntToUint64(footerStart) + if err != nil { + return fmt.Errorf("refstore/reftable: table %q: invalid footer offset: %w", table.name, err) + } if table.refIndexPos != 0 && table.refIndexPos < refEnd { refEnd = table.refIndexPos } @@ -188,13 +197,25 @@ func (table *tableFile) parseMeta() error { if logPos != 0 && logPos < refEnd { refEnd = logPos } - if refEnd < uint64(table.headerLen) || refEnd > uint64(len(table.data)) { + headerLenU64, err := intconv.IntToUint64(table.headerLen) + if err != nil { + return fmt.Errorf("refstore/reftable: table %q: invalid header length: %w", table.name, err) + } + dataLenU64, err := intconv.IntToUint64(len(table.data)) + if err != nil { + return fmt.Errorf("refstore/reftable: table %q: invalid data length: %w", table.name, err) + } + if refEnd < headerLenU64 || refEnd > dataLenU64 { return fmt.Errorf("refstore/reftable: table %q: invalid ref section", table.name) } - if table.refIndexPos > uint64(len(table.data)) { + if table.refIndexPos > dataLenU64 { return fmt.Errorf("refstore/reftable: table %q: invalid ref index position", table.name) } - table.refEnd = int(refEnd) + refEndInt, err := intconv.Uint64ToInt(refEnd) + if err != nil { + return fmt.Errorf("refstore/reftable: table %q: invalid ref section end: %w", table.name, err) + } + table.refEnd = refEndInt return nil } diff --git a/refstore/shorten_test.go b/refstore/shorten_test.go index 1975ab3f..53e7e003 100644 --- a/refstore/shorten_test.go +++ b/refstore/shorten_test.go @@ -10,6 +10,7 @@ func TestShortenName(t *testing.T) { t.Parallel() t.Run("simple", func(t *testing.T) { + t.Parallel() got := refstore.ShortenName("refs/heads/main", []string{"refs/heads/main"}) if got != "main" { t.Fatalf("ShortenName simple = %q, want %q", got, "main") @@ -17,6 +18,7 @@ func TestShortenName(t *testing.T) { }) t.Run("ambiguous with tags", func(t *testing.T) { + t.Parallel() got := refstore.ShortenName( "refs/heads/main", []string{ @@ -30,6 +32,7 @@ func TestShortenName(t *testing.T) { }) t.Run("strict remote head ambiguity", func(t *testing.T) { + t.Parallel() // In strict mode, refs/remotes/%s/HEAD blocks shortening to "%s". got := refstore.ShortenName( "refs/heads/main", @@ -44,6 +47,7 @@ func TestShortenName(t *testing.T) { }) t.Run("deep fallback still shortens", func(t *testing.T) { + t.Parallel() // refs/remotes/origin/main conflicts with refs/heads/origin/main for // "origin/main", so it should fall back to "remotes/origin/main". got := refstore.ShortenName( @@ -59,6 +63,7 @@ func TestShortenName(t *testing.T) { }) t.Run("refs-prefix fallback", func(t *testing.T) { + t.Parallel() name := "refs/notes/review/topic" got := refstore.ShortenName(name, []string{name}) if got != "notes/review/topic" { |
