]> Sergey Matveev's repositories - public-inbox.git/commitdiff
mbox_lock: dotlock: chdir for relative lock paths
authorEric Wong <e@80x24.org>
Wed, 24 Mar 2021 09:23:28 +0000 (14:23 +0500)
committerEric Wong <e@80x24.org>
Wed, 24 Mar 2021 23:01:16 +0000 (23:01 +0000)
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.

lib/PublicInbox/MboxLock.pm
t/mbox_lock.t

index bea0e3253e6471b6f36637a66296f5b31835baaf..856b1e21c9f391d829c8a921d786b72b6919e635 100644 (file)
@@ -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;
        }
 }
 
index 3dc3b449cd2338209ff3a59894cfbe5fde8878df..c2fee0d4eb88d056f006480841c497c1ab3e5576 100644 (file)
@@ -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']);