File::AtomicWrite - writes files atomically via rename()
use File::AtomicWrite (); # Standalone method: requires filename and # input data (filehandle or scalar ref) File::AtomicWrite->write_file( { file => 'data.dat', input => $filehandle } ); # how paranoid are you? File::AtomicWrite->write_file( { file => '/etc/passwd', input => \$scalarref, CHECKSUM => 1, min_size => 100 } ); # OO interface my $aw = File::AtomicWrite->new({ file => 'name' }); my $tmp_fh = $aw->fh; my $tmp_file = $aw->filename; print $tmp_fh ... $aw->checksum($sha1_hexdigest); $aw->commit;
This module offers atomic file writes via a temporary file created in the same directory (and therefore, probably the same partition) as the specified file. After data has been written to the temporary file, the rename call is used to replace the target file. The module optionally supports various sanity checks (min_size, CHECKSUM) that help ensure the data is written without errors.
rename
Should anything go awry, the module will die or croak. All error messages created by the module will end with a newline, though those from submodules (File::Temp, File::Path) may not. All calls should be wrapped in eval blocks:
die
croak
eval { File::AtomicWrite->write_file(...); }; if ($@) { die "uh oh: $@"; }
The module attempts to flush and sync the temporary filehandle prior to the rename call. This may cause portability problems. If so, please let the author know. Also notify the author if false positives from the close call are observed.
flush
sync
close
write_file
Class method. Requires a hash reference that contains at minimum both the input and file options. Performs the various required steps in a single method call. Only if all checks pass will the input data be moved to the file file via rename. If not, the module will throw an error, and attempt to cleanup any temporary files created.
See "OPTIONS" for details on the various required and optional values that can be passed to write_file in a hash reference.
new
Takes the same options as write_file (excepting the input option), returns an object.
input
In the event a rollback is required, undef the File::AtomicWrite object. The object destructor should then unlink the temporary file. However, should the process receive a TERM, INT, or some other catchable signal that causes it to exit, the cleanup will not be run. This edge case will need to be handled by the caller. Consult perlipc(1) for more information on signal handling.
undef
my $aw = File::AtomicWrite->new({file => 'somefile'}); $SIG{TERM} = sub { undef $aw }; $SIG{INT} = sub { undef $aw }; ...
fh
Instance method, returns a filehandle for the temporary file.
filename
Instance method, returns the file name of the temporary file.
checksum
Instance method. Takes a single argument that should contain the Digest::SHA1 hexdigest of the data written to the temporary file. Enables the CHECKSUM option.
hexdigest
commit
Instance method. Call once finished with the temporary file. A number of sanity checks (if enabled via the appropriate option) will be performed. If these pass, the temporary file will be renamed to the real filename.
The write_file and new methods accept a number of options, supplied via a hash reference:
Mandatory. A filename in the current working directory, or a path to the file that will be eventually created. By default, the temporary file will be written into the parent directory of the file path. This default can be changed by using the tmpdir option.
If the MKPATH option is true, the module will attempt to create any missing directories. If the MKPATH option is false or not set, the module will throw an error should any parent directories of the file not exist.
Mandatory for the write_file method, illegal for the new method. Scalar reference, or otherwise some filehandle reference that can be looped over via <>. Supplies the data to be written to file.
<>
Template to supply to File::Temp. Defaults to a hopefully reasonable value if unset. NOTE: if customized, the template must contain a sufficient number of X that terminate the template string, as otherwise File::Temp will throw an error.
X
Specify a minimum size (in bytes) that the data written must exceed. If not, the module throws an error.
Accepts a Unix mode for chmod to be applied to the file. Usual throwing of error. NOTE: depending on the source of the mode, oct may be first required to convert it into an octal number:
chmod
oct
my $orig_mode = (stat $source_file)[2] & 07777; ...->write_file({ ..., mode => $orig_mode }); my $mode = '0644'; ...->write_file({ ..., mode => oct($mode) });
The module does not change umask, nor is there a means to specify the permissions on directories created if MKPATH is set.
umask
Accepts similar arguments to chown(1) to be applied via chown to the file. Usual throwing of error.
chown
...->write_file({ ..., owner => '0' }); ...->write_file({ ..., owner => '0:0' }); ...->write_file({ ..., owner => 'user:somegroup' });
If set to a directory, the temporary file will be written to this directory instead of by default to the parent directory of the target file. If the tmpdir is on a different partition than the parent directory for file, or if anything else goes awry, the module will throw an error, as rename(2) cannot operate across partition boundaries.
This option is advisable when writing files to include directories such as /etc/logrotate.d, as the programs that read include files from these directories may read even a temporary dot file while it is being written. To avoid this (slight but non-zero) risk, use the tmpdir option to write the configuration out in full under a different directory on the same partition.
/etc/logrotate.d
If this option exists, and CHECKSUM is true, the module will not create a Digest::SHA1 hexdigest of the data being written out to disk, but instead will rely on the value passed by the caller.
If true, Digest::SHA1 will be used to checksum the data read back from the disk against the checksum derived from the data written out to the temporary file.
Use the checksum option (or checksum method) to supply a Digest::SHA1 hexdigest checksum. This will spare the module the task of computing the checksum on the data being written.
If true, binmode is set on the temporary filehandle prior to writing the input data to it. Default is note to set binmode.
binmode
If true (default is false), attempt to create the parent directories of file should that directory not exist. If false, and the parent directory does not exist, the module throws an error. If the directory cannot be created, the module throws an error.
If true, this option will also attempt to create the tmpdir directory, if that option is set.
No known bugs.
Newer versions of this module may be available from CPAN.
If the bug is in the latest version, send a report to the author. Patches that fix problems or add new features are welcome.
http://github.com/thrig/File-AtomicWrite/tree/master
See perlport(1) for various portability problems possible with the rename call. Consult rename(2) or equivalent for the system for any caveats about this system call.
Supporting modules:
File::Temp, File::Path, File::Basename, Digest::SHA1
Alternatives, depending on the need, include:
IO::Atomic, File::Transaction, File::Transaction::Atomic, Directory::Transactional
Jeremy Mates, <jmates@sial.org>
Copyright 2009 by Jeremy Mates.
This program is free software; you can redistribute it and/or modify it under the Artistic license.
To install File::AtomicWrite, copy and paste the appropriate command in to your terminal.
cpanm
cpanm File::AtomicWrite
CPAN shell
perl -MCPAN -e shell install File::AtomicWrite
For more information on module installation, please visit the detailed CPAN module installation guide.