aboutsummaryrefslogtreecommitdiffhomepage
path: root/internal
diff options
context:
space:
mode:
authorOphestra <cat@gensokyo.uk>2026-06-07 01:21:00 +0900
committerOphestra <cat@gensokyo.uk>2026-06-07 01:21:00 +0900
commite192fca762c2a44743474db33e5c807aab68ce6b (patch)
treee731b9a96b9605b3e0dd60f050fe7a5353dc58eb /internal
parent7eafc7b1e4b895d1986280e192aa8d493fff8d96 (diff)
internal/pkg: check for unclean shutdown
This avoids running into nasty surprises opening a cache that suffered unclean shutdown due to power loss. All other parts of the cache are not prone to inconsistent state. Signed-off-by: Ophestra <cat@gensokyo.uk>
Diffstat (limited to 'internal')
-rw-r--r--internal/pkg/pkg.go31
-rw-r--r--internal/pkg/pkg_test.go43
2 files changed, 74 insertions, 0 deletions
diff --git a/internal/pkg/pkg.go b/internal/pkg/pkg.go
index b8a997d8..9a6d5201 100644
--- a/internal/pkg/pkg.go
+++ b/internal/pkg/pkg.go
@@ -2443,6 +2443,37 @@ func open(
c.unlock = func() {}
}
+ for _, name := range []string{
+ dirWork,
+ dirTemp,
+ } {
+ dents, err := os.ReadDir(base.Append(name).String())
+ if err != nil {
+ if errors.Is(err, os.ErrNotExist) {
+ continue
+ }
+ c.unlock()
+ return nil, err
+ }
+ if len(dents) != 0 {
+ c.unlock()
+ return nil, fmt.Errorf(
+ "%s is not empty, scrub likely required",
+ name,
+ )
+ }
+ }
+
+ if _, err := os.ReadDir(base.Append(
+ dirExecScratch,
+ ).String()); !errors.Is(err, os.ErrNotExist) {
+ c.unlock()
+ if err != nil {
+ return nil, err
+ }
+ return nil, errors.New(dirExecScratch + " is present, scrub likely required")
+ }
+
variantPath := base.Append(fileVariant).String()
if p, err := os.ReadFile(variantPath); err != nil {
if !errors.Is(err, os.ErrNotExist) {
diff --git a/internal/pkg/pkg_test.go b/internal/pkg/pkg_test.go
index ce11fa90..9a397898 100644
--- a/internal/pkg/pkg_test.go
+++ b/internal/pkg/pkg_test.go
@@ -1852,6 +1852,49 @@ func TestOpen(t *testing.T) {
t.Errorf("Open: error = %#v, want %#v", err, wantErr)
}
})
+
+ t.Run("dirty", func(t *testing.T) {
+ t.Parallel()
+
+ tempDir := check.MustAbs(t.TempDir())
+ if err := os.MkdirAll(tempDir.Append(
+ "cache",
+ "work",
+ "dirty",
+ ).String(), 0755); err != nil {
+ t.Fatal(err)
+ }
+
+ wantErr := errors.New("work is not empty, scrub likely required")
+ if _, err := pkg.Open(
+ t.Context(),
+ message.New(nil),
+ 0, 0, 0, tempDir.Append("cache"),
+ ); !reflect.DeepEqual(err, wantErr) {
+ t.Errorf("Open: error = %#v, want %#v", err, wantErr)
+ }
+ })
+
+ t.Run("scratch", func(t *testing.T) {
+ t.Parallel()
+
+ tempDir := check.MustAbs(t.TempDir())
+ if err := os.MkdirAll(tempDir.Append(
+ "cache",
+ "scratch",
+ ).String(), 0755); err != nil {
+ t.Fatal(err)
+ }
+
+ wantErr := errors.New("scratch is present, scrub likely required")
+ if _, err := pkg.Open(
+ t.Context(),
+ message.New(nil),
+ 0, 0, 0, tempDir.Append("cache"),
+ ); !reflect.DeepEqual(err, wantErr) {
+ t.Errorf("Open: error = %#v, want %#v", err, wantErr)
+ }
+ })
}
func TestExtensionRegister(t *testing.T) {