From 48803b1a62d0f0caf326a81e75437cde4078e545 Mon Sep 17 00:00:00 2001 From: Aly Raffauf Date: Mon, 10 Aug 2026 11:22:46 -0400 Subject: [PATCH] refactor: share target read validation --- internal/application/evaluation/target.go | 3 ++- internal/filesystem/target.go | 6 ++++++ internal/reconcile/target_snapshot.go | 3 ++- 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/internal/application/evaluation/target.go b/internal/application/evaluation/target.go index b0f8d94..1d48198 100644 --- a/internal/application/evaluation/target.go +++ b/internal/application/evaluation/target.go @@ -6,6 +6,7 @@ import ( "path/filepath" "github.com/alyraffauf/cattery/internal/failure" + "github.com/alyraffauf/cattery/internal/filesystem" "github.com/alyraffauf/cattery/internal/reconcile" ) @@ -61,7 +62,7 @@ type targetReadInput struct { func validateOpenedTarget(input targetReadInput) error { info, err := input.file.Stat() - if err != nil || !input.record.Target.Identity().SameFileInfo(info) || info.Mode().Perm() != input.record.Target.Mode() { + if err != nil || !filesystem.MatchesIdentityAndMode(input.record.Target.Identity(), info, input.record.Target.Mode()) { return failure.New(failure.Operational, input.commandLabel+": target changed "+input.path, err) } return nil diff --git a/internal/filesystem/target.go b/internal/filesystem/target.go index 987b3aa..a2ee6f5 100644 --- a/internal/filesystem/target.go +++ b/internal/filesystem/target.go @@ -35,6 +35,12 @@ func (f TargetFacts) Mode() fs.FileMode { return f.mode } // Payload returns the exact referent of a symlink entry. func (f TargetFacts) Payload() string { return f.payload } +// MatchesIdentityAndMode reports whether an opened entry still matches a +// captured identity and permission mode. +func MatchesIdentityAndMode(identity pathsafe.Identity, info os.FileInfo, mode fs.FileMode) bool { + return identity.SameFileInfo(info) && info.Mode().Perm() == mode +} + // KindOfIdentity classifies an existing identity without touching the path. func KindOfIdentity(identity pathsafe.Identity) EntryKind { mode := identity.Mode() diff --git a/internal/reconcile/target_snapshot.go b/internal/reconcile/target_snapshot.go index c4db377..58940d5 100644 --- a/internal/reconcile/target_snapshot.go +++ b/internal/reconcile/target_snapshot.go @@ -9,6 +9,7 @@ import ( "path/filepath" "github.com/alyraffauf/cattery/internal/deployment" + "github.com/alyraffauf/cattery/internal/filesystem" "github.com/alyraffauf/cattery/internal/pathsafe" ) @@ -142,7 +143,7 @@ func validateOpenedFile(snapshot TargetSnapshot, info os.FileInfo) error { if !info.Mode().IsRegular() { return fmt.Errorf("reconcile: target changed to non-regular file %s", snapshot.identity.Path()) } - if !snapshot.identity.SameFileInfo(info) || info.Mode().Perm() != snapshot.mode { + if !filesystem.MatchesIdentityAndMode(snapshot.identity, info, snapshot.mode) { return fmt.Errorf("reconcile: target identity or mode changed while reading %s", snapshot.identity.Path()) } return nil -- 2.51.2