Nice test. I uploaded 3 items:
- patch for Slurp.pm
- patch for test error.t
- new test atom1.t
The patch prevents the victim file from being deleted. If the temporary file
exists, the code croaks unconditionally, and the file is never written.
#
https://rt.cpan.org/Ticket/Display.html?id=86166
use warnings;
use strict;
use File::Slurp qw(write_file);
use Test::More tests => 3;
my $file = 'atom1.txt' ;
my $victim = "$file.$$";
write_file($victim, '');
ok(-f $victim, 'have a victim file');
# This must not destroy the victim
$@ = '';
eval { write_file($file, { 'atomic' => 1 }, 'foo') };
like($@, qr/atomic temporary file/, 'die if no filename');
ok(-f $victim, 'victim file still there');
unlink $victim;
--- ../File-Slurp-9999.19.orig/lib/File/Slurp.pm 2011-05-30 15:58:53.000000000 -0400
+++ lib/File/Slurp.pm 2015-09-18 11:20:12.294297000 -0400
@@ -446,6 +446,7 @@
# in atomic mode, we spew to a temp file so make one and save the original
# file name.
+ _check_file($file_name);
$orig_file_name = $file_name ;
$file_name .= ".$$" ;
}
@@ -614,6 +615,7 @@
#print "EXIST [$$existing_data]\n" ;
$opts->{atomic} = 1 ;
+ _check_file($file_name);
my $write_result =
eval { write_file( $file_name, $opts,
$prepend_data, $$existing_data ) ;
@@ -671,6 +673,7 @@
my( $edited_data ) = map { $edit_code->(); $_ } $$existing_data ;
$opts->{atomic} = 1 ;
+ _check_file($file_name);
my $write_result =
eval { write_file( $file_name, $opts, $edited_data ) } ;
@@ -724,6 +727,7 @@
my @edited_data = map { $edit_code->(); $_ } @$existing_data ;
$opts->{atomic} = 1 ;
+ _check_file($file_name);
my $write_result =
eval { write_file( $file_name, $opts, @edited_data ) } ;
@@ -807,6 +811,15 @@
return undef ;
}
+sub _check_file {
+ my $file = shift;
+ my $file_temp .= "$file.$$";
+ if (-e $file_temp) {
+ # We should unconditionally die
+ croak("Error: atomic temporary file ($file_temp) already exists");
+ }
+}
+
1;
__END__
@@ -1066,7 +1079,8 @@
file is closed it is renamed to the original file name (and rename is
an atomic operation on most OS's). If the program using this were to
crash in the middle of this, then the file with the pid suffix could
-be left behind.
+be left behind. If the temporary file already exists, the code will
+C<croak>, regardless of the C<err_mode> setting.
=head3 append
--- ../File-Slurp-9999.19.orig/t/error.t 2011-05-03 04:03:02.000000000 -0400
+++ t/error.t 2015-09-18 10:51:51.091968000 -0400
@@ -77,6 +77,7 @@
sub => \&prepend_file,
args => [ $file_name ],
error => qr/read_file/,
+ posttest => sub { unlink $file_name, "$file_name.$$" },
},
{
name => 'prepend_file write error',