File Coverage

blib/lib/Mail/Box/Locker/POSIX.pm
Criterion Covered Total %
statement 43 55 78.1
branch 7 20 35.0
condition 1 3 33.3
subroutine 11 12 91.6
pod 3 4 75.0
total 65 94 69.1


line stmt bran cond sub pod time code
1             # This code is part of Perl distribution Mail-Box version 4.01.
2             # The POD got stripped from this file by OODoc version 3.05.
3             # For contributors see file ChangeLog.
4              
5             # This software is copyright (c) 2001-2025 by Mark Overmeer.
6              
7             # This is free software; you can redistribute it and/or modify it under
8             # the same terms as the Perl 5 programming language system itself.
9             # SPDX-License-Identifier: Artistic-1.0-Perl OR GPL-1.0-or-later
10              
11              
12             package Mail::Box::Locker::POSIX;{
13             our $VERSION = '4.01';
14             }
15              
16 2     2   3401 use parent 'Mail::Box::Locker';
  2         4  
  2         15  
17              
18 2     2   146 use strict;
  2         13  
  2         53  
19 2     2   9 use warnings;
  2         4  
  2         165  
20              
21 2     2   12 use Log::Report 'mail-box', import => [ qw/__x error fault warning/ ];
  2         4  
  2         18  
22              
23 2     2   461 use Fcntl qw/F_WRLCK F_UNLCK F_SETLK/;
  2         6  
  2         135  
24 2     2   12 use Errno qw/EAGAIN/;
  2         5  
  2         1982  
25              
26             # fcntl() should not be used without XS: the below is sensitive
27             # for changes in the structure. However, at the moment it seems
28             # there are only two options: either SysV-style or BSD-style
29              
30             my $pack_pattern = $^O =~ /bsd|darwin/i ? '@20 s @256' : 's @256';
31              
32             #--------------------
33              
34             sub init($)
35 1     1 0 18 { my ($self, $args) = @_;
36 1 50       6 $args->{file} = $args->{posix_file} if $args->{posix_file};
37 1         10 $self->SUPER::init($args);
38             }
39              
40             sub name() { 'POSIX' }
41              
42             #--------------------
43              
44             sub _try_lock($)
45 1     1   4 { my ($self, $file) = @_;
46 1         10 my $p = pack $pack_pattern, F_WRLCK;
47 1   33     30 $? = fcntl($file, F_SETLK, $p) || ($!+0);
48 1         7 $?==0;
49             }
50              
51             sub _unlock($)
52 1     1   3 { my ($self, $file) = @_;
53 1         10 my $p = pack $pack_pattern, F_UNLCK;
54 1         21 fcntl $file, F_SETLK, $p;
55 1         3 $self;
56             }
57              
58              
59             sub lock()
60 2     2 1 2689 { my $self = shift;
61              
62 2 100       18 $self->hasLock
63             and warning(__x"folder {name} already lockf'd.", name => $self->folder), return 1;
64              
65 1         14 my $file = $self->filename;
66              
67 1 50       80 open my $fh, '+<:raw', $file
68             or fault __x"unable to open POSIX lock file {file} for {folder}", file => $file, $self->folder;
69              
70 1         13 my $timeout = $self->timeout;
71 1 50       7 my $end = $timeout eq 'NOTIMEOUT' ? -1 : $timeout;
72              
73 1         3 while(1)
74 1 50       5 { if($self->_try_lock($fh))
75 1         4 { $self->{MBLF_filehandle} = $fh;
76 1         7 return $self->SUPER::lock;
77             }
78              
79 0 0       0 $!==EAGAIN
80             or fault __x"will never get a POSIX lock on {file} for {folder}", file => $file, folder => $self->folder;
81              
82 0 0       0 --$end or last;
83 0         0 sleep 1;
84             }
85              
86 0         0 return 0;
87             }
88              
89              
90             sub isLocked()
91 0     0 1 0 { my $self = shift;
92 0         0 my $file = $self->filename;
93              
94 0 0       0 open my $fh, '<:raw', $file
95             or fault __x"unable to check lock file {file} for {folder}", file => $file, folder => $self->folder;
96              
97 0 0       0 $self->_try_lock($fh)==0 or return 0;
98 0         0 $self->_unlock($fh);
99 0         0 $fh->close;
100              
101 0         0 $self->SUPER::unlock;
102 0         0 1;
103             }
104              
105             sub unlock()
106 1     1 1 1032 { my $self = shift;
107              
108             $self->_unlock(delete $self->{MBLF_filehandle})
109 1 50       7 if $self->hasLock;
110              
111 1         39 $self->SUPER::unlock;
112 1         4 $self;
113             }
114              
115             1;