@@ -183,7 +183,12 @@ sub import {
183183 if ( $state_file -> {file_handle } ) {
184184
185185 # TODO probably need to check for failure, but then what do I do?
186- eval { flock $state_file -> {file_handle }, 8; };
186+ eval {
187+ local $SIG {' ALRM' } = sub { die " flock 8 timeout\n " ; };
188+ my $orig_alarm = alarm $state_file -> {flock_timeout };
189+ flock $state_file -> {file_handle }, 8;
190+ alarm $orig_alarm ;
191+ };
187192 close $state_file -> {file_handle };
188193 $state_file -> {file_handle } = undef ;
189194
@@ -217,58 +222,29 @@ sub import {
217222 return ;
218223 }
219224
220- # Tested directly because this is critical logic.
221225 sub _open {
222- my ($self ) = @_ ;
226+ my ( $self , $mode ) = @_ ;
223227 my $state_file = $self -> {state_file };
224228 $state_file -> throw(' Cannot open state file inside a call_unlocked call.' ) unless defined $self -> {lock_file };
225229
226- OPEN_FLOCK: {
227- sysopen ( my $fh , $state_file -> {file_name }, Fcntl::O_CREAT() | Fcntl::O_RDWR(), 0600 )
228- or $state_file -> throw(" Unable to open state file '$state_file ->{file_name}': $! " );
229-
230- $self -> _flock_after_open($fh );
231-
232- # We might have blocked on the flock() long enough for
233- # another process to have rename()d over the file that
234- # we just locked. So we need to ensure that the file we
235- # have locked is the same file as $state_file.
236- my $fh_inode = ( stat $fh )[1];
237- my $path_inode = ( stat $state_file -> {file_name } )[1];
238- if ( $fh_inode != $path_inode ) {
239- redo OPEN_FLOCK;
240- }
241-
242- $state_file -> {file_handle } = $fh ;
243- }
244- }
245-
246- sub _flock_after_open {
247- my ( $self , $fh ) = @_ ;
248-
249- my $timed_out ;
250-
230+ open my $fh , $mode , $state_file -> {file_name }
231+ or $state_file -> throw(" Unable to open state file '$state_file ->{file_name}': $! " );
251232 eval {
252- local $SIG {' ALRM' } = sub {
253- $timed_out = 1;
254- die " flock LOCK_EX timeout\n " ;
255- };
256-
257- my $orig_alarm = alarm $self -> {state_file }{flock_timeout };
258- flock $fh , Fcntl::LOCK_EX();
233+ local $SIG {' ALRM' } = sub { die " flock 2 timeout\n " ; };
234+ my $orig_alarm = alarm $state_file -> {flock_timeout };
235+ flock $fh , 2;
259236 alarm $orig_alarm ;
260237 1;
261238 } or do {
262239 close ($fh );
263-
264- if ($timed_out ) {
265- $self -> {state_file }-> throw(" Guard timed out trying to lock state file “$self ->{state_file}{flock_timeout}”." );
240+ if ( $@ eq " flock 2 timeout\n " ) {
241+ $state_file -> throw(' Guard timed out trying to open state file.' );
242+ }
243+ else {
244+ $state_file -> throw($@ );
266245 }
267-
268- $self -> {state_file }-> throw($@ );
269246 };
270-
271- return ;
247+ $state_file -> {file_handle } = $fh ;
272248 }
273249
274250 sub update_file {
@@ -277,33 +253,26 @@ sub import {
277253 $state_file -> throw(' Cannot update_file inside a call_unlocked call.' ) unless defined $self -> {lock_file };
278254
279255 if ( !$state_file -> {file_handle } ) {
280- $self -> _open();
256+ if ( -e $state_file -> {file_name } ) {
257+ $self -> _open(' +<' );
258+ }
259+ else {
260+ sysopen ( my $fh , $state_file -> {file_name }, &Fcntl::O_CREAT | &Fcntl::O_EXCL | &Fcntl::O_RDWR )
261+ or $state_file -> throw(" Cannot create state file '$state_file ->{file_name}': $! " );
262+ $state_file -> {file_handle } = $fh ;
263+ }
281264 }
265+ seek ( $state_file -> {file_handle }, 0, 0 );
266+ truncate ( $state_file -> {file_handle }, 0 )
267+ or $state_file -> throw(" Unable to truncate the state file: $! " );
282268
283- # Set UNLINK in case we die().
284- require File::Temp;
285- my ( $fh , $path ) = File::Temp::tempfile( DIR => $self -> {_file_dir }, UNLINK => 1 );
286-
287- # We lock the temp file so that it’s “pre-locked”
288- # when we rename() it into place below. That way the
289- # production path stays consistently locked.
290- $self -> _flock_after_open($fh );
291-
292- $state_file -> {data_object }-> save_to_cache($fh );
293-
294- rename $path => $state_file -> {file_name } or $state_file -> throw(" Failed to rename($path => $state_file ->{file_name}: $! " );
295-
296- flock $state_file -> {file_handle }, Fcntl::LOCK_UN();
297- close $state_file -> {file_handle };
298-
299- @{$state_file }{ ' file_handle' , ' file_size' , ' file_mtime' } = (
300- $fh ,
301- ( stat $fh )[ 7, 9 ],
302- );
269+ $state_file -> {data_object }-> save_to_cache( $state_file -> {file_handle } );
270+ $state_file -> {file_mtime } = ( stat ( $state_file -> {file_handle } ) )[9];
303271
304272 # Make certain we are at end of file.
305- seek ( $fh , 0, Fcntl::SEEK_END() ) or $state_file -> throw(" Unable to go to end of file “$state_file ->{file_name}”: $! " );
306-
273+ seek ( $state_file -> {file_handle }, 0, 2 )
274+ or $state_file -> throw(" Unable to go to end of file: $! " );
275+ $state_file -> {file_size } = tell ( $state_file -> {file_handle } );
307276 return ;
308277 }
309278
@@ -461,7 +430,7 @@ sub import {
461430
462431 # File is newer or a different size
463432 $guard ||= cPanel::StateFile::Guard-> new( { state => $self } );
464- $guard -> _open();
433+ $guard -> _open(' +< ' );
465434 $self -> {data_object }-> load_from_cache( $self -> {file_handle } );
466435 ( $self -> {file_mtime }, $self -> {file_size } ) = ( stat ( $self -> {file_handle } ) )[ 9, 7 ];
467436 }
0 commit comments