//go:build darwin || linux package safeio import ( "errors" "os" "path/filepath" "testing" ) func TestReadCanonicalRegularRejectsReplacementDuringRead(t *testing.T) { root := canonicalSafeioTempDir(t) path := filepath.Join(root, "schema.sql") replacement := filepath.Join(root, "replacement.sql") parked := filepath.Join(root, "parked.sql") contents := make([]byte, 64<<20) if err := os.WriteFile(path, contents, 0o600); err != nil { t.Fatal(err) } if err := os.WriteFile(replacement, contents, 0o600); err != nil { t.Fatal(err) } entered := make(chan struct{}) proceed := make(chan struct{}) result := make(chan error, 1) go func() { _, err := readCanonicalRegularWithHook(path, int64(len(contents)), func() { close(entered) <-proceed }) result <- err }() <-entered if err := os.Rename(path, parked); err != nil { t.Fatal(err) } if err := os.Rename(replacement, path); err != nil { t.Fatal(err) } close(proceed) err := <-result if !errors.Is(err, ErrUnsafeFile) { t.Fatalf("replacement during read error = %v, want ErrUnsafeFile", err) } } func canonicalSafeioTempDir(t *testing.T) string { t.Helper() root, err := filepath.EvalSymlinks(os.TempDir()) if err != nil { t.Fatal(err) } directory, err := os.MkdirTemp(root, "thothctl-safeio-test-") if err != nil { t.Fatal(err) } t.Cleanup(func() { _ = os.RemoveAll(directory) }) return directory }