From 63335ec1a2935e42358b022f5b3dd0332bdd739e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C5=8Dan?= Date: Fri, 13 Mar 2026 13:08:11 -0600 Subject: [PATCH] fix: update ctime on chmod and chown operations Real chmod(2) and chown(2) both update the inode change time (ctime). The mock implementations were missing this, causing stat() to return stale ctime values after permission or ownership changes. Co-Authored-By: Claude Opus 4.6 --- lib/Test/MockFile.pm | 4 +++- t/chmod.t | 13 +++++++++++++ t/chown.t | 16 ++++++++++++++++ 3 files changed, 32 insertions(+), 1 deletion(-) diff --git a/lib/Test/MockFile.pm b/lib/Test/MockFile.pm index f2a3f57e..bff2a1d9 100644 --- a/lib/Test/MockFile.pm +++ b/lib/Test/MockFile.pm @@ -3491,6 +3491,7 @@ sub __chown (@) { # -1 means "keep as is" — preserve the file's current value $mock->{'uid'} = $uid == -1 ? $mock->{'uid'} : $uid; $mock->{'gid'} = $gid == -1 ? $mock->{'gid'} : $gid; + $mock->{'ctime'} = time; $num_changed++; } @@ -3556,7 +3557,8 @@ sub __chmod (@) { next; } - $mock->{'mode'} = ( $mock->{'mode'} & S_IFMT ) | ( $mode & S_IFPERMS ); + $mock->{'mode'} = ( $mock->{'mode'} & S_IFMT ) | ( $mode & S_IFPERMS ); + $mock->{'ctime'} = time; $num_changed++; } diff --git a/t/chmod.t b/t/chmod.t index 16a1a0ac..7e831325 100644 --- a/t/chmod.t +++ b/t/chmod.t @@ -263,5 +263,18 @@ subtest( } ); +subtest( + 'chmod updates ctime' => sub { + my $file = Test::MockFile->file( '/chmod_ctime/file', 'data' ); + + my $ctime_before = ( stat '/chmod_ctime/file' )[10]; + sleep 1; + chmod 0600, '/chmod_ctime/file'; + my $ctime_after = ( stat '/chmod_ctime/file' )[10]; + + ok( $ctime_after > $ctime_before, 'ctime updated after chmod' ); + } +); + done_testing(); exit; diff --git a/t/chown.t b/t/chown.t index cbfde0d7..37dcf40a 100644 --- a/t/chown.t +++ b/t/chown.t @@ -244,5 +244,21 @@ subtest( } ); +subtest( + 'chown updates ctime' => sub { + my $file = Test::MockFile->file( + '/chown_ctime_test' => 'data', + { uid => 1000, gid => 1000 }, + ); + + my $ctime_before = ( stat '/chown_ctime_test' )[10]; + sleep 1; + chown -1, -1, '/chown_ctime_test'; + my $ctime_after = ( stat '/chown_ctime_test' )[10]; + + ok( $ctime_after > $ctime_before, 'ctime updated after chown' ); + } +); + done_testing(); exit;