]> diplodocus.org Git - minc/blobdiff - minc
implement lkopen_fcntl from nmh
[minc] / minc
diff --git a/minc b/minc
index 224e56a..db8cdff 100755 (executable)
--- a/minc
+++ b/minc
@@ -39,13 +39,16 @@ $SIG{'PIPE'} = 'IGNORE';
 
 use Data::Dumper;
 use Errno;
-use Fcntl qw(O_WRONLY O_EXCL O_CREAT);
+use Fcntl;
 use FileHandle;
+use File::FcntlLock;
 use File::Temp qw(tempfile);
 use File::stat;
 use Getopt::Long qw(:config gnu_getopt no_ignore_case);
 use Pod::Usage;
 
+use constant LOCK_TRIES => 60;
+
 our $VERSION = 1;
 
 # If a filter set's header is $MAGIC_TO_TOKEN, that set is compared
@@ -362,6 +365,44 @@ sub mark {
     close($fh) or die("close(>$fn): $!");
 }
 
+# Based on nmh's lkopen_fcntl
+# Return 0 for success, errno on failure.
+sub lkopen_fcntl {
+    my $file = shift;
+    my $access = shift;
+    my $mode = shift;
+    my $errno = 0;
+
+    # The assumption here is that if you open the file for writing, you
+    # need an exclusive lock.
+
+    my $tries = LOCK_TRIES;
+    for (;;) {
+        sysopen(my $fh, $file, $access, $mode) or die("sysopen($file): $!");
+
+        my $flk = File::FcntlLock->new;
+        $flk->l_start(0);
+        $flk->l_len(0);
+        $flk->l_type(($access & O_ACCMODE) == O_RDONLY ? F_RDLCK : F_WRLCK);
+        $flk->l_whence(SEEK_SET);
+
+        # Really should only retry on EAGAIN and EINTR...
+        if ($flk->lock($fh, F_SETLK)) {
+            return $fh, undef;
+        }
+
+        $errno = $flk->lock_errno;
+        close($fh) or die("close($file): $!");
+
+        if (--$tries == 0) {
+            last;
+        }
+        sleep(1);
+    }
+
+    return undef, $errno;
+}
+
 sub store_message {
     my $msg = shift;
     my $mhfolder = shift;