File Coverage

lib/App/GitFind/FileStatLs.pm
Criterion Covered Total %
statement 18 89 20.2
branch 0 32 0.0
condition 0 6 0.0
subroutine 6 10 60.0
pod 4 4 100.0
total 28 141 19.8


line stmt bran cond sub pod time code
1             package App::GitFind::FileStatLs;
2              
3             # Perl standard modules
4 1     1   948 use strict;
  1         2  
  1         25  
5 1     1   4 use warnings;
  1         2  
  1         19  
6 1     1   3 use Carp;
  1         2  
  1         43  
7 1     1   4 use Fcntl ':mode';
  1         1  
  1         252  
8 1     1   7 use POSIX qw(strftime);
  1         1  
  1         7  
9              
10              
11             require 5.006;
12             our $VERSION = '0.000002';
13              
14 1     1   2170 use parent 'Exporter';
  1         2  
  1         4  
15             our @EXPORT = qw(ls_stat format_mode);
16             our @EXPORT_OK = qw(stat_attr);
17             our %EXPORT_TAGS = ( all => [@EXPORT, @EXPORT_OK] );
18              
19             =head1 NAME
20              
21             App::GitFind::FileStatLs - Provide stat information in ls -l format
22              
23             =head1 SYNOPSIS
24              
25             B<NOTICE:> This is a copy of L<File::Stat::Ls> with modifications, as found at
26             L<https://github.com/cxw42/File-Stat-Ls>.
27              
28             use App::GitFind::FileStatLs;
29              
30             my $obj = App::GitFind::FileStatLs->new;
31             my $ls = $obj->ls_stat('/my/file/name.txt');
32             # E.g., " -r-xr-xr-x 1 root other 4523 Jul 12 09:49 /my/file/name.txt"
33              
34             =head1 MODIFICATIONS
35              
36             In L</ls_stat ($fn)>:
37              
38             =over
39              
40             =item *
41              
42             Never take a class parameter, i.e., cannot be called as
43             C<< App::GitFind::FileStatLs->ls_stat >> or
44             C<< App::GitFind::FileStatLs->new->ls_stat >>.
45              
46             =item *
47              
48             Do not call C<lstat> a second time.
49              
50             =item *
51              
52             Change output format
53              
54             =back
55              
56             General:
57              
58             =over
59              
60             =item *
61              
62             Update documentation
63              
64             =item *
65              
66             Lazily load L<Carp>
67              
68             =back
69              
70             =head1 DESCRIPTION
71              
72             This class contains methods to convert stat elements into ls format.
73             It exports two methods: C<format_mode> and C<ls_stat>.
74             The C<format_mode> is borrowed from L<Stat::lsMode> class by
75             Mark Jason Dominus. The C<ls_stat> will build a string formatted as
76             the output of 'ls -l'.
77              
78             =cut
79              
80             =head2 new ()
81              
82             Input variables:
83              
84             None
85              
86             Variables used or routines called:
87              
88             None
89              
90             How to use:
91              
92             my $obj = new App::GitFind::FileStatLs; # or
93             my $obj = App::GitFind::FileStatLs->new; # or
94              
95             Return: new empty or initialized App::GitFind::FileStatLs object.
96              
97             =cut
98              
99             sub new {
100 0     0 1   my $caller = shift;
101 0           my $caller_is_obj = ref($caller);
102 0   0       my $class = $caller_is_obj || $caller;
103 0           my $self = bless {}, $class;
104 0           my %arg = @_; # convert rest of inputs into hash array
105 0           foreach my $k ( keys %arg ) {
106 0 0         if ($caller_is_obj) {
107 0           $self->{$k} = $caller->{$k};
108             } else {
109 0           $self->{$k} = $arg{$k};
110             }
111             }
112 0           return $self;
113             }
114              
115             =head1 METHODS
116              
117             This class defines the following common methods, routines, and
118             functions.
119              
120             =head2 Exported Tag: All
121              
122             The C<:all> tag includes all the methods or sub-rountines
123             defined in this class.
124              
125             use App::GitFind::FileStatLs qw(:all);
126              
127             It includes the following sub-routines:
128              
129             =cut
130              
131             # ------ partial inline of Stat::lsMode v0.50 code
132             # (see http://www.plover.com/~mjd/perl/lsMode/
133             # for the complete module)
134             #
135             #
136             # Stat::lsMode
137             #
138             # Copyright 1998 M-J. Dominus
139             # (mjd-perl-lsmode@plover.com)
140             #
141             # You may distribute this module under the same terms as Perl itself.
142             #
143             # $Revision: 1.2 $ $Date: 2004/08/05 14:17:43 $
144              
145             =head2 format_mode ($mode)
146              
147             Input variables:
148              
149             $mode - the third element from stat
150              
151             Variables used or routines called:
152              
153             None
154              
155             How to use:
156              
157             my $md = $self->format_mode((stat $fn)[2]);
158              
159             Return: string with permission bits such as -r-xr-xr-x.
160              
161             =cut
162              
163             sub format_mode {
164 0 0   0 1   my $s = ref($_[0]) ? shift : (App::GitFind::FileStatLs->new);
165 0           my $mode = shift;
166 0           my %opts = @_;
167              
168 0           my @perms = qw(--- --x -w- -wx r-- r-x rw- rwx);
169 0           my @ftype = qw(. p c ? d ? b ? - ? l ? s ? ? ?);
170 0           $ftype[0] = '';
171 0           my $setids = ($mode & 07000)>>9;
172 0           my @permstrs = @perms[($mode&0700)>>6, ($mode&0070)>>3, $mode&0007];
173 0           my $ftype = $ftype[($mode & 0170000)>>12];
174              
175 0 0         if ($setids) {
176 0 0         if ($setids & 01) { # Sticky bit
177 0 0         $permstrs[2] =~ s/([-x])$/$1 eq 'x' ? 't' : 'T'/e;
  0            
178             }
179 0 0         if ($setids & 04) { # Setuid bit
180 0 0         $permstrs[0] =~ s/([-x])$/$1 eq 'x' ? 's' : 'S'/e;
  0            
181             }
182 0 0         if ($setids & 02) { # Setgid bit
183 0 0         $permstrs[1] =~ s/([-x])$/$1 eq 'x' ? 's' : 'S'/e;
  0            
184             }
185             }
186              
187 0           join '', $ftype, @permstrs;
188             }
189              
190             =head2 ls_stat ($fn)
191              
192             Input variables:
193              
194             $fn - file name
195              
196             Variables used or routines called:
197              
198             None
199              
200             How to use:
201              
202             my $ls = ls_stat($fn);
203             # NOT $self->ls_stat($fn) --- not supported
204              
205             Return: the ls string such as one of the following:
206              
207             -r-xr-xr-x 1 root other 4523 Jul 12 09:49 uniq
208             drwxr-xr-x 2 root other 2048 Jul 12 09:50 bin
209             lrwxrwxrwx 1 oracle7 dba 40 Jun 12 2002 linked.pl -> /opt/bin/linked2.pl
210              
211             The output B<includes> a trailing newline.
212              
213             =cut
214              
215             sub ls_stat {
216 0     0 1   my $fn = shift;
217 0           my ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,
218             $atime,$mtime,$ctime,$blksize,$blocks) = lstat $fn;
219 0           my $dft = "%b %d %Y";
220 0           my $ud = getpwuid($uid);
221 0           my $gd = getgrgid($gid);
222 0           my $fm = format_mode($mode);
223 0           my $mt = strftime $dft,localtime $mtime;
224 0 0         my $link_to = (($mode & S_IFLNK) == S_IFLNK ? " -> @{[readlink $fn]}" : "");
  0            
225 0           my $fmt = "%10s %3d %7s %4s %12d %12s %-s%s\n";
226 0           return sprintf $fmt, $fm,$nlink,$ud,$gd,$size,$mt,$fn,$link_to;
227             }
228              
229             =head2 stat_attr ($fn, $typ)
230              
231             Input variables:
232              
233             $fn - file name for getting stat attributes
234             ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,
235             $atime,$mtime,$ctime,$blksize,$blocks) = stat($fn);
236             $typ - what type of object that you want it to return.
237             The default is to return a hash containing filename, longname,
238             and a hash ref with all the element from stat.
239             SFTP - to return a Net::SFTP::Attributes object
240              
241             Variables used or routines called:
242              
243             ls_stat
244              
245             How to use:
246              
247             my $hr = $self->stat_attr($fn); # get hash ref
248             my %h = $self->stat_attr($fn); # get hash
249              
250             Return: C<$hr> or C<%h> where the hash elements depend on the type.
251             The default is to get a hash array with the following elements:
252              
253             filename - file name
254             longname - the ls_stat string for the file
255             a - the attributes of the file with the following elements:
256             dev,ino,mode,nlink,uid,gid,rdev,size,atime,mtime,
257             ctime,blksize,blocks
258              
259             If the type is SFTP, then it will only return a
260             L<Net::SFTP::Attributes> object with the following elements:
261              
262             flags,perm,uid,gid,size,atime,mtime
263              
264             =cut
265              
266             sub stat_attr {
267 0 0   0 1   my $s = ref($_[0]) ? shift : (App::GitFind::FileStatLs->new);
268 0           my ($fn,$typ) = @_;
269 0 0         (require Carp, Carp::croak "ERR: no file name for stat_attr.\n") if ! $fn;
270 0 0         return undef if ! $fn;
271 0           my $vs = 'dev,ino,mode,nlink,uid,gid,rdev,size,atime,mtime,';
272 0           $vs .= 'ctime,blksize,blocks';
273 0           my $v1 = 'flags,perm,uid,gid,size,atime,mtime';
274 0           my $ls = ls_stat $fn; chomp $ls;
  0            
275 0           my @a = (); my @v = ();
  0            
276 0           my $attr = {};
277 0 0 0       if ($typ && $typ =~ /SFTP/i) {
278 0           @v = split /,/, $v1;
279 0           @a = (stat($fn))[1,2,4,5,7,8,9];
280 0           %$attr = map { $v[$_] => $a[$_] } 0..$#a ;
  0            
281             # 'SSH2_FILEXFER_ATTR_SIZE' => 0x01,
282             # 'SSH2_FILEXFER_ATTR_UIDGID' => 0x02,
283             # 'SSH2_FILEXFER_ATTR_PERMISSIONS' => 0x04,
284             # 'SSH2_FILEXFER_ATTR_ACMODTIME' => 0x08,
285 0           $attr->{flags} = 0;
286 0           $attr->{flags} |= 0x01;
287 0           $attr->{flags} |= 0x02;
288 0           $attr->{flags} |= 0x04;
289 0           $attr->{flags} |= 0x08;
290 0 0         return wantarray ? %{$attr} : $attr;
  0            
291             } else {
292 0           @v = split /,/, $vs;
293 0           @a = stat($fn);
294 0           %$attr = map { $v[$_] => $a[$_] } 0..$#a ;
  0            
295             }
296 0           my %r = (filename=>$fn, longname=>$ls, a=>$attr);
297             # foreach my $k (keys %r) { print "$k=$r{$k}\n"; }
298             # foreach my $k (keys %a) { print "$k=$a{$k}\n"; }
299             # print "X: " . (wantarray ? %r : \%r) . "\n";
300 0 0         return wantarray ? %r : \%r;
301             }
302              
303             1;
304              
305             =head1 SEE ALSO (some of docs that I check often)
306              
307             L<Data::Describe>, L<Oracle::Loader>, L<CGI::Getopt>, L<File::Xcopy>,
308             L<Oracle::Trigger>, L<Debug::EchoMessage>, L<CGI::Getopt>, L<Dir::ls>, etc.
309              
310             =head1 AUTHOR
311              
312             Copyright (c) 2005 Hanming Tu. All rights reserved.
313             Portions Copyright (c) 2019 D3 Engineering, LLC.
314              
315             This package is free software and is provided "as is" without express
316             or implied warranty. It may be used, redistributed and/or modified
317             under the terms of the Perl Artistic License (see
318             http://www.perl.com/perl/misc/Artistic.html)
319              
320             =cut