aboutsummaryrefslogtreecommitdiff
path: root/refstore
diff options
context:
space:
mode:
Diffstat (limited to 'refstore')
-rw-r--r--refstore/loose/loose_test.go15
-rw-r--r--refstore/packed/packed_test.go12
-rw-r--r--refstore/refstore.go2
-rw-r--r--refstore/reftable/lookup.go46
-rw-r--r--refstore/reftable/reftable_test.go15
-rw-r--r--refstore/reftable/table.go31
-rw-r--r--refstore/shorten_test.go5
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" {