File Coverage

blib/lib/Stat/lsMode.pm
Criterion Covered Total %
statement 25 48 52.0
branch 9 40 22.5
condition n/a
subroutine 5 7 71.4
pod 2 4 50.0
total 41 99 41.4


line stmt bran cond sub pod time code
1             #
2             #
3             # Stat::lsMode
4             #
5             # Copyright 1998 M-J. Dominus
6             # (mjd-perl-lsmode@plover.com)
7             #
8             # You may distribute this module under the same terms as Perl itself.
9             #
10             # $Revision: 1.2 $ $Date: 1998/04/20 01:27:25 $
11              
12              
13             package Stat::lsMode;
14              
15             $VERSION = '0.50';
16              
17 1     1   2436 use Carp;
  1         2  
  1         90  
18 1     1   5 use Exporter;
  1         2  
  1         1241  
19             @ISA = qw(Exporter);
20             @EXPORT = qw(format_mode file_mode format_perms);
21              
22             @perms = qw(--- --x -w- -wx r-- r-x rw- rwx);
23             @ftype = qw(. p c ? d ? b ? - ? l ? s ? ? ?);
24             $ftype[0] = '';
25              
26             $NOVICE_MODE = 1; # Default on?
27             sub novice {
28 0     0 0 0 my $pack = shift;
29 0 0       0 croak "novice_mode requires one boolean argument" unless @_ == 1;
30 0         0 my $old = $NOVICE_MODE; # Should this be localized t $pack?
31 0         0 $NOVICE_MODE = $_[0];
32 0         0 $old;
33             }
34              
35             sub format_mode {
36 14 50   14 1 236 croak "format_mode requires a mode as an argument" unless @_ >= 1;
37 14         18 my $mode = shift;
38 14         19 my %opts = @_;
39              
40 14 50       26 unless (defined $mode) {
41 0 0       0 return wantarray() ? () : undef;
42             }
43              
44 14 50       35 _novice_warning($mode) if $NOVICE_MODE;
45              
46 14         17 my $setids = ($mode & 07000)>>9;
47 14         34 my @permstrs = @perms[($mode&0700)>>6, ($mode&0070)>>3, $mode&0007];
48 14         21 my $ftype = $ftype[($mode & 0170000)>>12];
49 14 50       26 my @ftype = $opts{no_ftype} ? () : ($ftype);
50            
51 14 50       25 if ($setids) {
52 0 0       0 if ($setids & 01) { # Sticky bit
53 0 0       0 $permstrs[2] =~ s/([-x])$/$1 eq 'x' ? 't' : 'T'/e;
  0         0  
54             }
55 0 0       0 if ($setids & 04) { # Setuid bit
56 0 0       0 $permstrs[0] =~ s/([-x])$/$1 eq 'x' ? 's' : 'S'/e;
  0         0  
57             }
58 0 0       0 if ($setids & 02) { # Setgid bit
59 0 0       0 $permstrs[1] =~ s/([-x])$/$1 eq 'x' ? 's' : 'S'/e;
  0         0  
60             }
61             }
62              
63 14 50       43 if (wantarray) {
64 0         0 (@ftype, @permstrs);
65             } else {
66 14         54 join '', @ftype, @permstrs;
67             }
68             }
69              
70             sub file_mode {
71 6 50   6 1 927 croak "file_mode requires one filename as an argument" unless @_ == 1;
72 6         8 my $file = shift;
73 6         145 my $mode = (lstat $file)[2];
74              
75 6 50       16 unless (defined $mode) {
76 0 0       0 if (wantarray) {
77 0         0 return ();
78             } else {
79 0 0       0 carp "Couldn't get mode for file `$file': $!" if $NOVICE_MODE;
80 0         0 return undef;
81             }
82             }
83              
84 6         11 format_mode($mode, @_);
85             }
86              
87              
88              
89              
90             sub format_perms {
91 0 0   0 0 0 croak "format_perms requires a permission mode as an argument" unless @_ == 1;
92 0         0 format_mode($_[0], no_ftype => 1);
93             }
94              
95             # None of these are really plausible modes.
96             # They are all almost certain to have occurred
97             # when someone used decimal instead of octal to specify a mode.
98              
99             @badmodes = (777, 775, 755, 770, 700, 750,
100             751,
101             666, 664, 644, 660, 600, 640,
102             444, 440,
103             400, # 400 = rw--w---- which is just barely plausible.
104             # 000 *is* OK. It means just what you think.
105             711, 771, 751, 551, 111,
106             );
107             %badmode = map {($_ => 1)} @badmodes;
108              
109             # Novices like to ask for the bits for mode `666' instead of `0666'.
110             # Try to detect and diagnose that.
111             sub _novice_warning {
112 14     14   14 my $mode = shift;
113 14 50       35 if ($badmode{$mode}) {
114 0           carp "mode $mode is very surprising. Perhaps you meant 0$mode";
115             }
116             }
117              
118             =head1 NAME
119              
120             Stat::lsMode - format file modes like the C command does
121              
122             =head1 SYNOPSIS
123              
124             use Stat::lsMode;
125              
126             $mode = (stat $file)[2];
127             $permissions = format_mode($mode);
128             # $permissions is now something like `drwxr-xr-x'
129              
130             $permissions = file_mode($file); # Same as above
131              
132             $permissions = format_perms(0644); # Produces just 'rw-r--r--'
133              
134             $permissions = format_perms(644); # This generates a warning message:
135             # mode 644 is very surprising. Perhaps you meant 0644...
136              
137             Stat::lsMode->novice(0); # Disable warning messages
138              
139             =head1 DESCRIPTION
140              
141             C generates mode and permission strings that look like
142             the ones generated by the Unix C command. For example, a
143             regular file that is readable by everyone and writable only by its
144             owner has the mode string C<-rw-r--r-->. C will either
145             examine the file and produce the right mode string for you, or you can
146             pass it the mode that you get back from Perl's C call.
147              
148             =head2 C
149              
150             Given a mode number (such as the third element of the list returned by
151             C), return the appopriate ten-character mode string as it would
152             have been generated by C. For example,
153             consider a directory that is readable and searchable by everyone, and
154             also writable by its owner. Such a directory will have mode 040755.
155             When passed this value, C will return the string
156             C.
157              
158             If C is passed a permission number like C<0755>, it will
159             return a nine-character string insted, with no leading character to
160             say what the file type is. For example, C will
161             return just C, without the leading C.
162              
163             =head2 C
164              
165             Given a filename, do C on the file to determine the mode, and
166             return the mode, formatted as above.
167              
168             =head2 Novice Operation Mode
169              
170             A common mistake when dealing with permission modes is to use C<644>
171             where you meant to use C<0644>. Every permission has a numeric
172             representation, but the representation only makes sense when you write
173             the number in octal. The decimal number 644 corresponds to a
174             permission setting, but not the one you think. If you write it in
175             octal you get 01204, which corresponds to the unlikely permissions
176             C<-w----r-T>, not to C.
177              
178             The appearance of the bizarre permission C<-w----r-T> in a program is
179             almost a sure sign that someone used C<644> when they meant to use
180             C<0644>. By default, this module will detect the use of such unlikely
181             permissions and issue a warning if you try to format them. To disable
182             these warnings, use
183              
184             Stat::lsMode->novice(0); # disable novice mode
185              
186             Stat::lsMode->novice(1); # enable novice mode again
187              
188             The surprising permissions that are diagnosed by this mode are:
189              
190             111 => --xr-xrwx
191             400 => rw--w----
192             440 => rw-rwx---
193             444 => rw-rwxr--
194             551 => ---r--rwt
195             600 => --x-wx--T
196             640 => -w------T
197             644 => -w----r-T
198             660 => -w--w-r-T
199             664 => -w--wx--T
200             666 => -w--wx-wT
201             700 => -w-rwxr-T
202             711 => -wx---rwt
203             750 => -wxr-xrwT
204             751 => -wxr-xrwt
205             751 => -wxr-xrwt
206             755 => -wxrw--wt
207             770 => r------wT
208             771 => r------wt
209             775 => r-----rwt
210             777 => r----x--t
211              
212             Of these, only 400 is remotely plausible.
213              
214             =head1 BUGS
215              
216             As far as I know, the precise definition of the mode bits is portable
217             between varieties of Unix. The module should, however, examine
218             C or use some other method to find out if there are any local
219             variations, because Unix being Unix, someone somewhere probably does
220             it differently.
221              
222             Maybe it C should have an option that says that if the file
223             is a symlink, to format the mode of the pointed to file instead of the
224             mode of the link itself, the way C does.
225              
226             =head1 SEE ALSO
227              
228             =over 4
229              
230             =item *
231              
232             C.
233              
234             =item *
235              
236             L
237              
238             =item *
239              
240             L
241              
242             =item *
243              
244             L
245              
246             =back
247              
248             =head1 AUTHOR
249              
250             Mark-Jason Dominus (C).
251              
252             =cut
253