Skip Menu |

This queue is for tickets about the File-Listing CPAN distribution.

Report information
The Basics
Id: 71054
Status: resolved
Priority: 0/
Queue: File-Listing

People
Owner: Nobody in particular
Requestors: peter.john.acklam [...] gmail.com
Cc:
AdminCc:

Bug Information
Severity: Normal
Broken in: 6.02
Fixed in: (no value)



Subject: file_mode() is broken
1) file_mode() doesn't recognize when the set-user-ID bit (file mode bit 04000), set-group-ID bit (file mode bit 02000), or sticky bit (file mode bit 01000) is set. For instance, the following perl -MFile::Listing -we 'printf "%05o", 07777 & File::Listing::file_mode(shift)' -- -rwsrwsrwt prints "00776", but should print "07777". (The reason for the bug is that the file type character is stripped off with the line "s/^(.)// and $type = $1;", so the later code, "$mode |= 0004000 if /^..s....../i; ..." will never match.) 2) The output above also reveals another bug, that file_mode() doesn't handle the least significant bit (file mode bit 00001) properly, since it returns "...76", not "...77". 3) When the set-group-ID bit (file mode bit 02000) is set, and the group execution bit (file mode bit 00020) is unset, and it is a regular file, some implementations of "ls" use the letter "S", others use "l" or "L". For instance, the mode "07767" might be reported as "rwsrwlrwx", "rwsrwSrwx", or "rwsrwLrwx". file_mode() doesn't handle the variants using "l" or "L". 4) file_mode() only knows about directories, symlinks, and regular files. It would be nice if it also knew about fifos (pipes) etc. I have attached a patch and four test files, testing all 4096 possible permission modes (00000 .. 07777) given by for 4 different implementations of "ls". Not all implementations of "ls" map the 4096 unique input values to 4096 unique strings, though.
Subject: File-Listing.pm.patch
--- lib/File/Listing.pm.orig 2011-03-20 12:42:00.000000000 +0100 +++ lib/File/Listing.pm 2011-09-18 13:00:42.000000000 +0200 @@ -35,30 +35,47 @@ sub file_mode ($) { + Carp::croak("Input to file_mode() must be a 10 character string.") + unless length($_[0]) == 10; + # This routine was originally borrowed from Graham Barr's # Net::FTP package. local $_ = shift; my $mode = 0; - my($type,$ch); + my($type); s/^(.)// and $type = $1; + # When the set-group-ID bit (file mode bit 02000) is set, and the group + # execution bit (file mode bit 00020) is unset, and it is a regular file, + # some implementations of `ls' use the letter `S', others use `l' or `L'. + # Convert this `S'. + + s/[Ll](...)$/S$1/; + while (/(.)/g) { $mode <<= 1; $mode |= 1 if $1 ne "-" && $1 ne 'S' && - $1 ne 't' && $1 ne 'T'; } - $type eq "d" and $mode |= 0040000 or # Directory - $type eq "l" and $mode |= 0120000 or # Symbolic Link - $mode |= 0100000; # Regular File - - $mode |= 0004000 if /^...s....../i; - $mode |= 0002000 if /^......s.../i; - $mode |= 0001000 if /^.........t/i; + $mode |= 0004000 if /^..s....../i; + $mode |= 0002000 if /^.....s.../i; + $mode |= 0001000 if /^........t/i; + + # De facto standard definitions. From 'stat.h' on Solaris 9. + + $type eq "p" and $mode |= 0010000 or # fifo + $type eq "c" and $mode |= 0020000 or # character special + $type eq "d" and $mode |= 0040000 or # directory + $type eq "b" and $mode |= 0060000 or # block special + $type eq "-" and $mode |= 0100000 or # regular + $type eq "l" and $mode |= 0120000 or # symbolic link + $type eq "s" and $mode |= 0140000 or # socket + $type eq "D" and $mode |= 0150000 or # door + Carp::croak("Unknown file type: $type"); $mode; }
Subject: perm3.t

Message body is not shown because it is too large.

Subject: perm4.t

Message body is not shown because it is too large.

Subject: perm2.t

Message body is not shown because it is too large.

Subject: perm1.t

Message body is not shown because it is too large.