diff --git a/internal/pkg/pkg.go b/internal/pkg/pkg.go index dd48d84..59662b1 100644 --- a/internal/pkg/pkg.go +++ b/internal/pkg/pkg.go @@ -665,6 +665,9 @@ type ScrubError struct { // Dangling identifier symlinks. This can happen if the content-addressed // entry was removed while scrubbing due to a checksum mismatch. DanglingIdentifiers []ID + // Dangling status files. This can happen if a dangling status symlink was + // removed while scrubbing. + DanglingStatus []ID // Miscellaneous errors, including [os.ReadDir] on checksum and identifier // directories, [Decode] on entry names and [os.RemoveAll] on inconsistent // entries. @@ -716,6 +719,13 @@ func (e *ScrubError) Error() string { } segments = append(segments, s) } + if len(e.DanglingStatus) > 0 { + s := "dangling status:\n" + for _, id := range e.DanglingStatus { + s += Encode(id) + "\n" + } + segments = append(segments, s) + } if len(e.Errs) > 0 { s := "errors during scrub:\n" for pathname, errs := range e.errs { @@ -894,6 +904,36 @@ func (c *Cache) Scrub(checks int) error { wg.Wait() } + dir = c.base.Append(dirStatus) + if entries, readdirErr := os.ReadDir(dir.String()); readdirErr != nil { + if !errors.Is(readdirErr, os.ErrNotExist) { + addErr(dir, readdirErr) + } + } else { + wg.Add(len(entries)) + for _, ent := range entries { + w <- checkEntry{ent, func(ent os.DirEntry, want *Checksum) bool { + got := p.Get().(*Checksum) + defer p.Put(got) + + if _, err := os.Stat(c.base.Append( + dirIdentifier, + ent.Name(), + ).String()); err != nil { + if !errors.Is(err, os.ErrNotExist) { + addErr(dir.Append(ent.Name()), err) + } + seMu.Lock() + se.DanglingStatus = append(se.DanglingStatus, *want) + seMu.Unlock() + return false + } + return true + }} + } + wg.Wait() + } + if len(c.identPending) > 0 { addErr(c.base, errors.New( "scrub began with pending artifacts", @@ -924,6 +964,7 @@ func (c *Cache) Scrub(checks int) error { if len(se.ChecksumMismatches) > 0 || len(se.DanglingIdentifiers) > 0 || + len(se.DanglingStatus) > 0 || len(se.Errs) > 0 { slices.SortFunc(se.ChecksumMismatches, func(a, b ChecksumMismatchError) int { return bytes.Compare(a.Want[:], b.Want[:]) @@ -931,6 +972,9 @@ func (c *Cache) Scrub(checks int) error { slices.SortFunc(se.DanglingIdentifiers, func(a, b ID) int { return bytes.Compare(a[:], b[:]) }) + slices.SortFunc(se.DanglingStatus, func(a, b ID) int { + return bytes.Compare(a[:], b[:]) + }) return &se } else { return nil