Is there a way to create a file that is locked at the time of creation in Perl?

I need to create a file that is locked for reading at the time of creation, so that other processes that can look for this file do not start reading it before it is completely written.

I know that I can create and then block it, but I am worried that this leaves me open to the conditions of the race.

Or am I not worried about anything here? If I have a file open for writing and then open it for reading by another process, will the reading process never see EOF until the writing process closes the file?

+4
source share
3 answers

There is a race condition with > and >> , but it can be circumvented with +< .

 # > open(my $fh, '+<', $qfn) or die $!; flock($fh, LOCK_EX) or die $!; truncate($fh, 0) or die $!; ... # >> open(my $fh, '+<', $qfn) or die $!; flock($fh, LOCK_EX) or die $!; seek($fh, 0, SEEK_END) or die $!; ... 

There is also a race condition in the scenario you are describing.

 Writer Reader ========================= ========================= - opens file - opens file - locks file - obtains lock on file - locks file [blocks] - reads the file [empty] - closes and unlocks file - obtains lock on file - writes to file - writes to file - closes and unlocks file 

A common strategy to avoid this problem is to have a writer

  • create a file in a temporary directory and then
  • rename file to a directory that the reader monitors when the file is completed.

rename is an atomic action, so the file will be completely formed in the directory that the reader is viewing. This requires the cooperation of a writer, but better solutions will be.

+7
source

Use umask(0777) before creating the file.

Writing a file to the file system will be completely unavailable [*] (ie permissions ---------- ), even if the file descriptor you still allow recording.

Then the chmod() file after completion:

 my $file = 'foo.txt'; my $umask = umask(0777); # change the umask open(OUT, '>', $file); # create the file umask($umask); # reset the umask print OUT "testing\n"; # put stuff in your file close(OUT); # finished with that... chmod(0644, $file); # change the permissions 

NB: this is not really a β€œlock” in the strict sense, where the operating system actively prevents access to files. This is the β€œcrack” level of the file system - if you cannot actually open the file, it will sort the lock.

[*] except root processe.

(FWIW, reading a semi-recorded file will result in an EOF condition.)

+9
source

Either this is supported on your operating system or not. If so, then easy and simple.

 use Fcntl qw( O_CREAT O_EXCL O_WRONLY O_EXLOCK ); $creat_flags = (O_CREAT | O_EXCL | O_WRONLY | O_EXLOCK ); sysopen(SOMEHANDLE, $somepath, $creat_flags, 0666) || die "$0: couldn't sysopen $somepath with flags $creat_flags: $!"; 
+3
source

All Articles