| File::AtomicWrite - writes files atomically via rename |
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 writes files out atomically by first creating a temporary
filehandle, then using the rename() function to overwrite the target
file. The module optionally supports size tests on the output file
(to help avoid a zero byte passwd file and the resulting
headaches, for example).
Should anything go awry, the module will die or croak as
appropriate. All error messages created by the module will end with a
newline, though those from submodules (File::Temp,
the File::Path manpage) may not. Therefore, all calls should be wrapped in
eval blocks:
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.
write_file
Class method. Requires a hash reference that contains 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 same options as write_file (excepting the input option),
returns an object.
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 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. See perlipc(1) for more
information on signal handling.
my $aw = File::AtomicWrite->new({file => 'somefile'});
$SIG{TERM} = { 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.
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 method accepts 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, instead of issuing an error.
Mandatory. 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.
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:
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.
Accepts similar arguments to chown(1) to be applied via chown
to the file. Usual throwing of error.
...->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.
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.
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. See also the checksum option.
If true, binmode() is set on the temporary filehandle prior to
writing the input data to it.
If true (default is false), attempt to create the parent directory 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 set.
No known bugs.
=head2 Reporting 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.
Supporting modules:
File::Temp, File::Path, File::Basename, Digest::SHA1
Alternatives, depending on the need, include:
IO::Atomic, File::Transaction, File::Transaction::Atomic
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.
| File::AtomicWrite - writes files atomically via rename |