File Coverage

blib/lib/Mail/Box/Locker/FcntlLock.pm
Criterion Covered Total %
statement 13 15 86.6
branch n/a
condition n/a
subroutine 5 5 100.0
pod n/a
total 18 20 90.0


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::FcntlLock;{
13             our $VERSION = '4.01';
14             }
15              
16 1     1   8 use parent 'Mail::Box::Locker';
  1         2  
  1         8  
17              
18 1     1   91 use strict;
  1         2  
  1         30  
19 1     1   6 use warnings;
  1         2  
  1         69  
20              
21 1     1   7 use Log::Report 'mail-box', import => [ qw/__x error fault warning/ ];
  1         2  
  1         26  
22              
23 1     1   670 use File::FcntlLock ();
  0            
  0            
24             use Fcntl qw/F_WRLCK F_SETLK F_UNLCK/;
25             use Errno qw/EAGAIN/;
26              
27             #--------------------
28              
29             sub init($)
30             { my ($self, $args) = @_;
31             $args->{file} = $args->{posix_file} if $args->{posix_file};
32             $self->SUPER::init($args);
33             }
34              
35             sub name() { 'FcntlLock' }
36              
37             #--------------------
38              
39             sub _try_lock($)
40             { my ($self, $file) = @_;
41             my $fl = File::FcntlLock->new;
42             $fl->l_type(F_WRLCK);
43             $? = $fl->lock($file, F_SETLK);
44             $?==0;
45             }
46              
47             sub _unlock($)
48             { my ($self, $file) = @_;
49             my $fl = File::FcntlLock->new;
50             $fl->l_type(F_UNLCK);
51             $fl->lock($file, F_SETLK);
52             $self;
53             }
54              
55              
56             sub lock()
57             { my $self = shift;
58              
59             if($self->hasLock)
60             { my $folder = $self->folder;
61             warning __x"folder {name} already lockf'd.", name => $folder;
62             return 1;
63             }
64              
65             my $file = $self->filename;
66             open my $fh, '+<:raw', $file
67             or fault __x"unable to open FcntlLock lock file {file} for {folder}", file => $file, folder => $self->folder;
68              
69             my $timeout = $self->timeout;
70             my $end = $timeout eq 'NOTIMEOUT' ? -1 : $timeout;
71              
72             while(1)
73             { if($self->_try_lock($fh))
74             { $self->SUPER::lock;
75             $self->{MBLF_filehandle} = $fh;
76             return 1;
77             }
78              
79             $!==EAGAIN
80             or fault __x"will never get a FcntlLock lock on {file} for {folder}", file => $file, folder => $self->folder;
81              
82             --$end or last;
83             sleep 1;
84             }
85              
86             return 0;
87             }
88              
89              
90             sub isLocked()
91             { my $self = shift;
92              
93             my $file = $self->filename;
94             open my $fh, '<:raw', $file
95             or fault __x"unable to check lock file {file} for {folder}", file => $file, folder => $self->folder;
96              
97             $self->_try_lock($fh)==0 or return 0;
98             $self->_unlock($fh);
99             $fh->close;
100              
101             $self->SUPER::unlock;
102             1;
103             }
104              
105             sub unlock()
106             { my $self = shift;
107              
108             $self->_unlock(delete $self->{MBLF_filehandle})
109             if $self->hasLock;
110              
111             $self->SUPER::unlock;
112             $self;
113             }
114              
115             1;