snafu has asked for the wisdom of the Perl Monks concerning the following question:

In my search I found the following nodes File permission converter and Converting Permission string to Octal. However, these are working the problem I am faced with in a backward manner to my situation.

I have written a lil perl script that stats files for mac times (mtime, atime, ctime) and some other various tidbits of data. One these data is the absolute permissions mode. I want to convert these modes to the all too recognizeable masked notation eg. drwxrwxrwx.

I am currently using bitwise operations to get something (not sure what it is though because it isn't the real permissions mode of the file as far as I can tell). I will post the script and the output.

#!/usr/local/bin/perl -w # Written by Jim Conner # 4/10/2001 # Nifty lil utility I wrote to be able to # get the mtime, ctime, and atime values from # any file of your choice. ################################################### # HOW TO USE!! # It is quite simple. All you do is supply this # script with the directory(ies)/file(s) you want to get # info on and voila! there's your info. # # Examples: # # macls /tmp # This will give you a listing of all files in /tmp # # macls file1 file2 file3 # This will give you a listing of files 1 2 and 3. # # macls # This will give you a listing of all files in the # present working directory. # # TODO: # Add command line args and options. One of the # most important of which would be -h (help) # # Fix the mode. Currently, it does not report # an understandable mode. # # Translate the mode to human readable (laman) # terms (drwxrwxr-x) # # Audit Trail: # 4/9/2k1 - First conceptualized and started on authoring # 4/10/2k1 - Released version 1.0 # ################################################### use strict; use File::Basename; use vars qw($DEBUG); #################### $DEBUG = "0"; #################### my $plProgName = basename($0); my $count = "0"; my $total = "0"; my @filename; #################### if ( $#ARGV == "-1" ) { @filename = &readall(); } elsif ( $#ARGV >= "0" ) { if ( -d $ARGV[0] ) { @filename = &readall($ARGV[0]); } else { @filename = @ARGV; } } print "\n"; for ( @filename ) { my $filename = $_; my($dev,$inode,$mode,$nlink,$uid,$gid,$rdev,$size,$atime,$mtime,$c +time,$blksize,$blocks); if ( $count >= "1" ) { print "******************************************************* +\n\n"; } warn "$0: $filename: $!\n" and next if ( ! open (F,"$filename") ); # I just found this :( # 0 dev device number of filesystem # 1 ino inode number # 2 mode file mode (type and permissions) # 3 nlink number of (hard) links to the file # 4 uid numeric user ID of file's owner # 5 gid numeric group ID of file's owner # 6 rdev the device identifier (special files only) # 7 size total size of file, in bytes # 8 atime last access time since the epoch # 9 mtime last modify time since the epoch # 10 ctime inode change time (NOT creation time!) since the epoch +<-- NNNOOOTTT GOOD!! :( # 11 blksize preferred block size for file system I/O # 12 blocks actual number of blocks allocated # #(The epoch was at 00:00 January 1, 1970 GMT.) ($dev, $inode, $mode, $nlink, $uid, $gid, $rdev, $size, $atime, $mtime, $ctime, $blksize, $blocks ) = lstat(F); # from mknod(2) (good info!) # S_ISUID 04000 Set user ID on execution. # S_ISGID 020#0 Set group ID on execution if # is 7, 5, 3, +or 1. # Enable mandatory file/record locking if # i +s # 6, 4, 2, or 0. # S_ISVTX 01000 Save text image after execution. # S_IRWXU 00700 Read, write, execute by owner. # S_IRUSR 00400 Read by owner. # S_IWUSR 00200 Write by owner. # S_IXUSR 00100 Execute (search if a directory) by owner. # S_IRWXG 00070 Read, write, execute by group. # S_IRGRP 00040 Read by group. # S_IWGRP 00020 Write by group. # S_IXGRP 00010 Execute by group. # S_IRWXO 00007 Read, write, execute (search) by others. # S_IROTH 00004 Read by others. # S_IWOTH 00002 Write by others # S_IXOTH 00001 Execute by others. # S_ISVTX On directories, restricted deletion flag. $mode &= 07777; my $username = getpwuid($uid); my $grpname = getgrgid($gid); my @atime_readable = &fixgmt("$atime",'atime'); my @mtime_readable = &fixgmt("$mtime",'mtime'); my @ctime_readable = &fixgmt("$ctime",'ctime'); print "MACtime for: $filename\n"; print "Mode($mode) $username($uid) $grpname($gid)\t$size bytes $b +locks blocks\n"; print "Modified time\t........ @mtime_readable\n"; print "Access time \t........ @atime_readable\n"; print "Inode Change \t........ @ctime_readable\n\n"; close(F); $count++; $total = $total + $size; } print "\nTotal files checked : $count\n"; print "Total size in bytes : $total\n"; printf("Total size in Kbytes: %iK\n", $total / 1024); printf("Total size in Mbytes: %iM\n\n", ($total / 1024) / 1024); sub fixgmt() { my ($object, $type) = @_ ; print gmtime($object) ."\n" if $DEBUG == "1"; my($aday,$mon,$nday,$gmtime,$year) = split(/\s+/,gmtime($object)); my($hour,$min,$sec) = split(/:/,$gmtime); # Do math on gmt time to make it localtime. # Should get this from system LCTIME but I dunno # how to do that yet...sooo # Im gonna brute force the math for now. $hour = abs($hour - 4); $hour = "0$hour" if ( $hour < 10 ); $nday = "0$nday" if ( $nday < 10 ); my $ltime = "$hour:$min:$sec"; if ( $DEBUG == "1" ) { print "Object type is: $type\n"; print "Object value is: $object\n"; print "Alpha day = $aday\nMonth = $mon\nNumber day = + $nday\nGMTTime = $gmtime\nYear = $year\n"; print "Hour = $hour\nMinute = $min\nSecond = $sec\n" +; print "LocalTime = $ltime\n\n"; } return($aday,$mon,$nday,$ltime,$year); } sub readall() { my $dir = "@_" ; if ( $dir ) { chdir($dir); opendir(ALL,".") or die("Unable to read: $!\n"); } else { opendir(ALL,".") or die("Unable to read: $!\n"); } my @files = grep(!/(^\.\.?)/,readdir(ALL)) or die("Unable to get f +ile list: $!\n"); return(@files); }
I would appreciate a couple of things. Constructive code criticism. This will help me learn as I am still (what I consider to be) extremely new to Perl. May hurt my pride some but oh well. I would also like to find out how to get the permissions thing to work right. More specifically, how to get the proper permissions (ie 0755, or 0644, or 4750). Once I get to that point, I believe I can take it from there (to be seen). Here is what I get for output:
[jconner@kwan ~/bin/dev]$ perl macls macls

MACtime for: macls
Mode(416) jconner(10036) other(1)       5727 bytes  12 blocks
Modified time   ........ Wed May 23 17:37:57 2001
Access time     ........ Wed May 23 17:42:24 2001
Inode Change    ........ Wed May 23 17:37:57 2001


Total files checked : 1
Total size in bytes : 5727
Total size in Kbytes: 5K
Total size in Mbytes: 0M

The part that says: mode (416) is the obvious broken part and where I need the most help. The permissions the filesystem sees is 640.
[jconner@kwan ~/bin/dev]$ ls -l macls
-rw-r-----    1 jconner  other        5727 May 23 17:37 macls
I appreciate any assistance in advance. Thanks everyone!

----------
- Jim

Edited 2001-05-24 by Ovid

Replies are listed 'Best First'.
Re: Fellow Monks please lend an ear...suggestions/comments on how to convert absolute (octal) file permission to Unix notation...
by mikfire (Deacon) on May 24, 2001 at 02:34 UTC
    Hmm. I hate it when this happens. You are printing the number in its *decimal* representation, not the octal. To see the mode in octal, you need printf:
    printf "Mode(%04o) $username(%s) $grpname(%s)\t%d bytes %d blocks\n", + $mode, $uid, $gid, $size, $blocks;
    should show you what you are expecting.

    mikfire

Re: Fellow Monks please lend an ear...suggestions/comments on how to convert absolute (octal) file permission to Unix notation...
by traveler (Parson) on May 24, 2001 at 02:48 UTC
    Your mode code is correct (sort of). The *nix mode is octal (which is base 8). You printed it in base 10! 0x640 == 416. You need to break out the bits of the mode with, say, bitwise and (&) (depending on your algorithm you might be able to use vec). If you require 'sys/stat.ph'; you'll get some useful constants to help you decode the mode. Check the *nix manual for stat(2) to find out more about those useful constants...

    localtime might be useful, too.

    --traveler