about summary refs log tree commit homepage
diff options
context:
space:
mode:
authorEric Wong <e@80x24.org>2021-03-24 14:23:28 +0500
committerEric Wong <e@80x24.org>2021-03-24 23:01:16 +0000
commit5577a83631e057a31489aa1ce8d1d35ac33f9d7d (patch)
treee489fb96caff09cc7dd17dfa510f33bd5e65760e
parentc882fd47f0f83f0be9b8c524604e003295e2b1ba (diff)
downloadpublic-inbox-5577a83631e057a31489aa1ce8d1d35ac33f9d7d.tar.gz
Since lei-daemon will fchdir on every request, we must ensure
we're in the correct directory before unlink(2) is called,
since we can't use unlinkat(2) from pure Perl.
-rw-r--r--lib/PublicInbox/MboxLock.pm14
-rw-r--r--t/mbox_lock.t12
2 files changed, 26 insertions, 0 deletions
diff --git a/lib/PublicInbox/MboxLock.pm b/lib/PublicInbox/MboxLock.pm
index bea0e325..856b1e21 100644
--- a/lib/PublicInbox/MboxLock.pm
+++ b/lib/PublicInbox/MboxLock.pm
@@ -60,6 +60,11 @@ sub acq_dotlock {
                         if (link($tmp, $dot_lock)) {
                                 unlink($tmp) or die "unlink($tmp): $!";
                                 $self->{".lock$pid"} = $dot_lock;
+                                if (substr($dot_lock, 0, 1) ne '/') {
+                                        opendir(my $dh, '.') or
+                                                        die "opendir . $!";
+                                        $self->{dh} = $dh;
+                                }
                                 return;
                         }
                         unlink($tmp) or die "unlink($tmp): $!";
@@ -111,10 +116,19 @@ sub acq {
         $self;
 }
 
+sub _fchdir { chdir($_[0]) } # OnDestroy callback
+
 sub DESTROY {
         my ($self) = @_;
         if (my $f = $self->{".lock$$"}) {
+                my $x;
+                if (my $dh = delete $self->{dh}) {
+                        opendir my $c, '.' or die "opendir . $!";
+                        $x = PublicInbox::OnDestroy->new(\&_fchdir, $c);
+                        chdir($dh) or die "chdir (for $f): $!";
+                }
                 unlink($f) or die "unlink($f): $! (lock stolen?)";
+                undef $x;
         }
 }
 
diff --git a/t/mbox_lock.t b/t/mbox_lock.t
index 3dc3b449..c2fee0d4 100644
--- a/t/mbox_lock.t
+++ b/t/mbox_lock.t
@@ -5,6 +5,7 @@ use strict; use v5.10.1; use PublicInbox::TestCommon;
 use POSIX qw(_exit);
 use PublicInbox::DS qw(now);
 use Errno qw(EAGAIN);
+use PublicInbox::OnDestroy;
 use_ok 'PublicInbox::MboxLock';
 my ($tmpdir, $for_destroy) = tmpdir();
 my $f = "$tmpdir/f";
@@ -15,6 +16,17 @@ ok(!-f "$f.lock", 'dotlock gone');
 $mbl = PublicInbox::MboxLock->acq($f, 1, ['none']);
 ok(!-f "$f.lock", 'no dotlock with none');
 undef $mbl;
+{
+        opendir my $cur, '.' or BAIL_OUT $!;
+        my $od = PublicInbox::OnDestroy->new(sub { chdir $cur });
+        chdir $tmpdir or BAIL_OUT;
+        my $abs = "$tmpdir/rel.lock";
+        my $rel = PublicInbox::MboxLock->acq('rel', 1, ['dotlock']);
+        chdir '/' or BAIL_OUT;
+        ok(-f $abs, 'lock with abs path created');
+        undef $rel;
+        ok(!-f $abs, 'lock gone despite being in the wrong dir');
+}
 
 eval {
         PublicInbox::MboxLock->acq($f, 1, ['bogus']);