File Coverage

blib/lib/File/chmod.pm
Criterion Covered Total %
statement 92 164 56.1
branch 80 232 34.4
condition 13 23 56.5
subroutine 18 33 54.5
pod 7 28 25.0
total 210 480 43.7


line stmt bran cond sub pod time code
1             package File::chmod;
2 5     5   300763 use strict;
  5         11  
  5         189  
3 5     5   32 use warnings;
  5         11  
  5         157  
4 5     5   111 use Carp;
  5         9  
  5         385  
5 5     5   24 use vars qw( $VAL $W $MODE );
  5         9  
  5         355  
6              
7 5     5   41 use base 'Exporter';
  5         13  
  5         15594  
8              
9             our $VERSION = '0.40'; # VERSION
10              
11             our @EXPORT = (qw( chmod getchmod )); ## no critic ( ProhibitAutomaticExportation )
12             our @EXPORT_OK = (qw( symchmod lschmod getsymchmod getlschmod getmod ));
13              
14             our $DEBUG = 1;
15             our $UMASK = 2;
16             our $MASK = umask;
17              
18              
19             my ($SYM,$LS) = (1,2);
20             my %ERROR = (
21             EDETMOD => "use of determine_mode is deprecated",
22             ENEXLOC => "cannot set group execute on locked file",
23             ENLOCEX => "cannot set file locking on group executable file",
24             ENSGLOC => "cannot set-gid on locked file",
25             ENLOCSG => "cannot set file locking on set-gid file",
26             ENEXUID => "execute bit must be on for set-uid",
27             ENEXGID => "execute bit must be on for set-gid",
28             ENULSID => "set-id has no effect for 'others'",
29             ENULSBG => "sticky bit has no effect for 'group'",
30             ENULSBU => "sticky bit has no effect for 'user'",
31             );
32              
33             sub getmod {
34 31     31 1 1737 my @return = map { (stat)[2] & 07777 } @_;
  31         718  
35 31 100       255 return wantarray ? @return : $return[0];
36             }
37              
38              
39             sub chmod (@) { ## no critic ( Subroutines::ProhibitBuiltinHomonyms Subroutines::ProhibitSubroutinePrototypes )
40 19     19 1 1852 my $mode = shift;
41 19         45 my $how = mode($mode);
42              
43 19 100       80 return symchmod($mode,@_) if $how == $SYM;
44 2 50       13 return lschmod($mode,@_) if $how == $LS;
45 2         61 return CORE::chmod($mode,@_);
46             }
47              
48              
49             sub getchmod {
50 0     0 1 0 my $mode = shift;
51 0         0 my $how = mode($mode);
52              
53 0 0       0 return getsymchmod($mode,@_) if $how == $SYM;
54 0 0       0 return getlschmod($mode,@_) if $how == $LS;
55 0 0       0 return wantarray ? (($mode) x @_) : $mode;
56             }
57              
58              
59             sub symchmod {
60 17     17 1 25 my $mode = shift;
61              
62 17         48 my @return = getsymchmod($mode,@_);
63 17         21 my $ret = 0;
64 17 50       30 for (@_){ $ret++ if CORE::chmod(shift(@return),$_) }
  17         517  
65 17         124 return $ret;
66             }
67              
68              
69             sub getsymchmod {
70 17     17 1 23 my $mode = shift;
71 17         20 my @return;
72              
73 17 50       33 croak "symchmod received non-symbolic mode: $mode" if mode($mode) != $SYM;
74              
75 17         44 for (@_){
76 17         36 local $VAL = getmod($_);
77              
78 17         75 for my $this (split /,/, $mode){
79 17         23 local $W = 0;
80 17         22 my $or;
81              
82 17         45 for (split //, $this){
83 49 100 100     235 if (not defined $or and /[augo]/){
84 15 50       36 /a/ and $W |= 7, next;
85 15 100       42 /u/ and $W |= 1, next;
86 8 100       25 /g/ and $W |= 2, next;
87 4 50       31 /o/ and $W |= 4, next;
88             }
89              
90 34 100       91 if (/[-+=]/){
91 17   100     62 $W ||= 7;
92 17 100       60 $or = (/[=+]/ ? 1 : 0);
93 17 50       67 clear() if /=/;
94 17         26 next;
95             }
96              
97 17 50       39 croak "Bad mode $this" if not defined $or;
98 17 50       54 croak "Unknown mode: $mode" if !/[ugorwxslt]/;
99              
100 17 0       40 /u/ and $or ? u_or() : u_not();
    50          
101 17 0       37 /g/ and $or ? g_or() : g_not();
    50          
102 17 0       54 /o/ and $or ? o_or() : o_not();
    50          
103 17 100       155 /r/ and $or ? r_or() : r_not();
    100          
104 17 100       50 /w/ and $or ? w_or() : w_not();
    100          
105 17 100       88 /x/ and $or ? x_or() : x_not();
    100          
106 17 0       40 /s/ and $or ? s_or() : s_not();
    50          
107 17 0       125 /l/ and $or ? l_or() : l_not();
    50          
108 17 100       86 /t/ and $or ? t_or() : t_not();
    100          
109             }
110             }
111 17 50       47 $VAL &= ~$MASK if $UMASK;
112 17         39 push @return, $VAL;
113             }
114 17 50       64 return wantarray ? @return : $return[0];
115             }
116              
117              
118             sub lschmod {
119 0     0 1 0 my $mode = shift;
120              
121 0         0 return CORE::chmod(getlschmod($mode,@_),@_);
122             }
123              
124              
125             sub getlschmod {
126 0     0 1 0 my $mode = shift;
127 0         0 my $VAL = 0;
128              
129 0 0       0 croak "lschmod received non-ls mode: $mode" if mode($mode) != $LS;
130              
131 0         0 my ($u,$g,$o) = ($mode =~ /^.(...)(...)(...)$/);
132              
133 0         0 for ($u){
134 0 0       0 $VAL |= 0400 if /r/;
135 0 0       0 $VAL |= 0200 if /w/;
136 0 0       0 $VAL |= 0100 if /[xs]/;
137 0 0       0 $VAL |= 04000 if /[sS]/;
138             }
139              
140 0         0 for ($g){
141 0 0       0 $VAL |= 0040 if /r/;
142 0 0       0 $VAL |= 0020 if /w/;
143 0 0       0 $VAL |= 0010 if /[xs]/;
144 0 0       0 $VAL |= 02000 if /[sS]/;
145             }
146              
147 0         0 for ($o){
148 0 0       0 $VAL |= 0004 if /r/;
149 0 0       0 $VAL |= 0002 if /w/;
150 0 0       0 $VAL |= 0001 if /[xt]/;
151 0 0       0 $VAL |= 01000 if /[Tt]/;
152             }
153              
154 0 0       0 return wantarray ? (($VAL) x @_) : $VAL;
155             }
156              
157              
158             sub mode {
159 36     36 0 44 my $mode = shift;
160 36 100       141 return 0 if $mode !~ /\D/;
161 34 100       134 return $SYM if $mode =~ /[augo=+,]/;
162 8 50       22 return $LS if $mode =~ /^.([r-][w-][xSs-]){2}[r-][w-][xTt-]$/;
163 8         19 return $SYM;
164             }
165              
166              
167             sub determine_mode {
168 0     0 0 0 carp $ERROR{EDECMOD};
169 0         0 mode(@_);
170             }
171              
172              
173             sub clear {
174 0 0   0 0 0 $W & 1 and $VAL &= 02077;
175 0 0       0 $W & 2 and $VAL &= 05707;
176 0 0       0 $W & 4 and $VAL &= 07770;
177             }
178              
179              
180             sub u_or {
181 0     0 0 0 my $val = $VAL;
182 0 0       0 $W & 2 and ($VAL |= (($val & 0700)>>3 | ($val & 04000)>>1));
183 0 0       0 $W & 4 and ($VAL |= (($val & 0700)>>6));
184             }
185              
186              
187             sub u_not {
188 0     0 0 0 my $val = $VAL;
189 0 0       0 $W & 1 and $VAL &= ~(($val & 0700) | ($val & 05000));
190 0 0       0 $W & 2 and $VAL &= ~(($val & 0700)>>3 | ($val & 04000)>>1);
191 0 0       0 $W & 4 and $VAL &= ~(($val & 0700)>>6);
192             }
193              
194              
195             sub g_or {
196 0     0 0 0 my $val = $VAL;
197 0 0       0 $W & 1 and $VAL |= (($val & 070)<<3 | ($val & 02000)<<1);
198 0 0       0 $W & 4 and $VAL |= ($val & 070)>>3;
199             }
200              
201              
202             sub g_not {
203 0     0 0 0 my $val = $VAL;
204 0 0       0 $W & 1 and $VAL &= ~(($val & 070)<<3 | ($val & 02000)<<1);
205 0 0       0 $W & 2 and $VAL &= ~(($val & 070) | ($val & 02000));
206 0 0       0 $W & 4 and $VAL &= ~(($val & 070)>>3);
207             }
208              
209              
210             sub o_or {
211 0     0 0 0 my $val = $VAL;
212 0 0       0 $W & 1 and $VAL |= (($val & 07)<<6);
213 0 0       0 $W & 2 and $VAL |= (($val & 07)<<3);
214             }
215              
216              
217             sub o_not {
218 0     0 0 0 my $val = $VAL;
219 0 0       0 $W & 1 and $VAL &= ~(($val & 07)<<6);
220 0 0       0 $W & 2 and $VAL &= ~(($val & 07)<<3);
221 0 0       0 $W & 4 and $VAL &= ~($val & 07);
222             }
223              
224              
225             sub r_or {
226 4 50   4 0 12 $W & 1 and $VAL |= 0400;
227 4 100       10 $W & 2 and $VAL |= 0040;
228 4 100       12 $W & 4 and $VAL |= 0004;
229             }
230              
231              
232             sub r_not {
233 4 50   4 0 10 $W & 1 and $VAL &= ~0400;
234 4 100       10 $W & 2 and $VAL &= ~0040;
235 4 100       11 $W & 4 and $VAL &= ~0004;
236             }
237              
238              
239             sub w_or {
240 1 50   1 0 5 $W & 1 and $VAL |= 0200;
241 1 50       6 $W & 2 and $VAL |= 0020;
242 1 50       5 $W & 4 and $VAL |= 0002;
243             }
244              
245              
246             sub w_not {
247 1 50   1 0 5 $W & 1 and $VAL &= ~0200;
248 1 50       5 $W & 2 and $VAL &= ~0020;
249 1 50       4 $W & 4 and $VAL &= ~0002;
250             }
251              
252              
253             sub x_or {
254 1 0   1 0 4 if ($VAL & 02000){ $DEBUG and carp($ERROR{ENEXLOC}), return }
  0 50       0  
255 1 50       6 $W & 1 and $VAL |= 0100;
256 1 50       3 $W & 2 and $VAL |= 0010;
257 1 50       3 $W & 4 and $VAL |= 0001;
258             }
259              
260              
261             sub x_not {
262 1 50   1 0 5 $W & 1 and $VAL &= ~0100;
263 1 50       4 $W & 2 and $VAL &= ~0010;
264 1 50       4 $W & 4 and $VAL &= ~0001;
265             }
266              
267              
268             sub s_or {
269 0 0   0 0 0 if ($VAL & 02000){ $DEBUG and carp($ERROR{ENSGLOC}), return }
  0 0       0  
270 0 0       0 if (not $VAL & 00100){ $DEBUG and carp($ERROR{ENEXUID}), return }
  0 0       0  
271 0 0       0 if (not $VAL & 00010){ $DEBUG and carp($ERROR{ENEXGID}), return }
  0 0       0  
272 0 0       0 $W & 1 and $VAL |= 04000;
273 0 0       0 $W & 2 and $VAL |= 02000;
274 0 0 0     0 $W & 4 and $DEBUG and carp $ERROR{ENULSID};
275             }
276              
277              
278             sub s_not {
279 0 0   0 0 0 $W & 1 and $VAL &= ~04000;
280 0 0       0 $W & 2 and $VAL &= ~02000;
281 0 0 0     0 $W & 4 and $DEBUG and carp $ERROR{ENULSID};
282             }
283              
284              
285             sub l_or {
286 0 0   0 0 0 if ($VAL & 02010){ $DEBUG and carp ($ERROR{ENLOCSG}), return }
  0 0       0  
287 0 0       0 if ($VAL & 00010){ $DEBUG and carp ($ERROR{ENLOCEX}), return }
  0 0       0  
288 0         0 $VAL |= 02000;
289             }
290              
291              
292             sub l_not {
293 0 0   0 0 0 $VAL &= ~02000 if not $VAL & 00010;
294             }
295              
296              
297             sub t_or {
298 3 50 66 3 0 656 $W & 1 and $DEBUG and carp $ERROR{ENULSBU};
299 3 50 66     216 $W & 2 and $DEBUG and carp $ERROR{ENULSBG};
300 3 100       17 $W & 4 and $VAL |= 01000;
301             }
302              
303              
304             sub t_not {
305 2 50 66 2 0 243 $W & 1 and $DEBUG and carp $ERROR{ENULSBU};
306 2 50 66     254 $W & 2 and $DEBUG and carp $ERROR{ENULSBG};
307 2 50       12 $W & 4 and $VAL &= ~01000;
308             }
309              
310              
311             1;
312             # ABSTRACT: Implements symbolic and ls chmod modes
313              
314             __END__