Debian lenny version packages
[pkg-perl] / deb-src / libio-stringy-perl / io-stringy-2.110 / lib / IO / AtomicFile.pm
1 package IO::AtomicFile;
2
3 ### DOCUMENTATION AT BOTTOM OF FILE
4
5 # Be strict:
6 use strict;
7
8 # External modules:
9 use IO::File;
10
11
12 #------------------------------
13 #
14 # GLOBALS...
15 #
16 #------------------------------
17 use vars qw($VERSION @ISA);
18
19 # The package version, both in 1.23 style *and* usable by MakeMaker:
20 $VERSION = "2.110";
21
22 # Inheritance:
23 @ISA = qw(IO::File);
24
25
26 #------------------------------
27 # new ARGS...
28 #------------------------------
29 # Class method, constructor.
30 # Any arguments are sent to open().
31 #
32 sub new {
33     my $class = shift;
34     my $self = $class->SUPER::new();
35     ${*$self}{'io_atomicfile_suffix'} = '';
36     $self->open(@_) if @_;
37     $self;
38 }
39
40 #------------------------------
41 # DESTROY 
42 #------------------------------
43 # Destructor.
44 #
45 sub DESTROY {
46     shift->close(1);   ### like close, but raises fatal exception on failure
47 }
48
49 #------------------------------
50 # open PATH, MODE
51 #------------------------------
52 # Class/instance method.
53 #
54 sub open {
55     my ($self, $path, $mode) = @_;
56     ref($self) or $self = $self->new;    ### now we have an instance! 
57
58     ### Create tmp path, and remember this info: 
59     my $temp = "${path}..TMP" . ${*$self}{'io_atomicfile_suffix'};
60     ${*$self}{'io_atomicfile_temp'} = $temp;
61     ${*$self}{'io_atomicfile_path'} = $path;
62
63     ### Open the file!  Returns filehandle on success, for use as a constructor: 
64     $self->SUPER::open($temp, $mode) ? $self : undef;
65 }
66
67 #------------------------------
68 # _closed [YESNO]
69 #------------------------------
70 # Instance method, private.
71 # Are we already closed?  Argument sets new value, returns previous one.
72 #
73 sub _closed {
74     my $self = shift;
75     my $oldval = ${*$self}{'io_atomicfile_closed'};
76     ${*$self}{'io_atomicfile_closed'} = shift if @_;
77     $oldval;
78 }
79
80 #------------------------------
81 # close
82 #------------------------------
83 # Instance method.
84 # Close the handle, and rename the temp file to its final name.
85 #
86 sub close {
87     my ($self, $die) = @_;
88     unless ($self->_closed(1)) {             ### sentinel...
89         $self->SUPER::close();    
90         rename(${*$self}{'io_atomicfile_temp'},
91                ${*$self}{'io_atomicfile_path'}) 
92             or ($die ? die "close atomic file: $!\n" : return undef); 
93     }
94     1;
95 }
96
97 #------------------------------
98 # delete
99 #------------------------------
100 # Instance method.
101 # Close the handle, and delete the temp file.
102 #
103 sub delete {
104     my $self = shift;
105     unless ($self->_closed(1)) {             ### sentinel...
106         $self->SUPER::close();    
107         return unlink(${*$self}{'io_atomicfile_temp'});
108     }
109     1;
110 }
111
112 #------------------------------
113 # detach
114 #------------------------------
115 # Instance method.
116 # Close the handle, but DO NOT delete the temp file.
117 #
118 sub detach {
119     my $self = shift;
120     $self->SUPER::close() unless ($self->_closed(1));
121     1;
122 }
123
124 #------------------------------
125 1;
126 __END__
127
128
129 =head1 NAME
130
131 IO::AtomicFile - write a file which is updated atomically
132
133
134 =head1 SYNOPSIS
135
136     use IO::AtomicFile;
137
138     ### Write a temp file, and have it install itself when closed:
139     my $FH = IO::AtomicFile->open("bar.dat", "w");
140     print $FH "Hello!\n";
141     $FH->close || die "couldn't install atomic file: $!";    
142
143     ### Write a temp file, but delete it before it gets installed:
144     my $FH = IO::AtomicFile->open("bar.dat", "w");
145     print $FH "Hello!\n";
146     $FH->delete; 
147
148     ### Write a temp file, but neither install it nor delete it:
149     my $FH = IO::AtomicFile->open("bar.dat", "w");
150     print $FH "Hello!\n";
151     $FH->detach;   
152
153
154 =head1 DESCRIPTION
155
156 This module is intended for people who need to update files 
157 reliably in the face of unexpected program termination.  
158
159 For example, you generally don't want to be halfway in the middle of
160 writing I</etc/passwd> and have your program terminate!  Even
161 the act of writing a single scalar to a filehandle is I<not> atomic.
162
163 But this module gives you true atomic updates, via rename().
164 When you open a file I</foo/bar.dat> via this module, you are I<actually> 
165 opening a temporary file I</foo/bar.dat..TMP>, and writing your
166 output there.   The act of closing this file (either explicitly
167 via close(), or implicitly via the destruction of the object)
168 will cause rename() to be called... therefore, from the point
169 of view of the outside world, the file's contents are updated
170 in a single time quantum.
171
172 To ensure that problems do not go undetected, the "close" method
173 done by the destructor will raise a fatal exception if the rename()
174 fails.  The explicit close() just returns undef.   
175
176 You can also decide at any point to trash the file you've been 
177 building. 
178
179
180 =head1 AUTHOR
181
182 =head2 Primary Maintainer
183
184 David F. Skoll (F<dfs@roaringpenguin.com>).
185
186 =head2 Original Author
187
188 Eryq (F<eryq@zeegee.com>).
189 President, ZeeGee Software Inc (F<http://www.zeegee.com>).
190
191
192 =head1 REVISION
193
194 $Revision: 1.2 $
195
196 =cut