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

Monks:

I am trying to figure out how to use the 1st byte of the permissions string that is returned by stat. If I use the test -l operator it confirms that my file is a link, but when I use the technique below which I got from your site. It returns a - instead of an l for link. For directories and regular files it does return the correct value.

Now to be honest I don't really understand what the & 07777 and the 0170000 do as shown in the example below. Is it some sort of masking? I am very new to perl so any help would be greatly appreciated.

Code Excerpt:

@ftypes = qw(. p c ? d ? b ? - ? l ? s ? ? ?); ($dev,$inode,$mode,$nlink,$uid,$gid,$rdev,$size, $atime,$mtime,$ctime,$blksize,$blocks) = stat($source_file); $perms = $mode & 07777; $filetype = $ftypes[($mode & 0170000)>>12];
Below is entire script...
#!/usr/bin/perl # # get information about a file # # define source file parameter which is a link $source_file = "/temp/test/source/dir1/hello1_link.txt"; # define filetype array with potential first bits of mode @ftypes = qw(. p c ? d ? b ? - ? l ? s ? ? ?); $ftypes0 = ''; # Get File Statistics Using Scalar context ($dev,$inode,$mode,$nlink,$uid,$gid,$rdev,$size, $atime,$mtime,$ctime,$blksize,$blocks) = stat($source_file); $perms = $mode & 07777; $octperms = sprintf("%lo", $perms); $filetype = $ftypes[($mode & 0170000)>>12]; # Try to Id a link using lstat $stat = lstat($source_file); octperms = sprintf("%lo", $perms); $filetype = $ftypes[($mode & 0170000)>>12]; # Try to Id a link using lstat $stat = lstat($source_file); if ( -l _) { print ("link identified using -l _ and lstat\n"); $link = "Y"; } # Try to Id a link with explicit -l test operator if ( -l $source_file) { print ("link identified using -l test operator \n"); $link = "Y"; + } print ("source_file = $source_file \n"); print ("uid = $uid \n"); print ("gid = $gid \n"); print ("mode = $mode \n"); print ("perms = $perms \n"); print ("octperms = $octperms \n"); print ("filetype = $filetype \n"); print ("link = $link \n"); print ("nlink = $nlink \n"); link identified using -l _ and lstat link identified using -l test operator source_file = /temp/test/source/dir1/hello1_link.txt uid = 14442 gid = 554 mode = 164349 perms = 509 octperms = 775 filetype = - link = Y nlink = 1

Replies are listed 'Best First'.
Re: Unix File Type with stat
by Zaxo (Archbishop) on Sep 10, 2002 at 05:47 UTC

    Yes, 0170000 and 0007777 are octal masks, the first for file types, the second for permissions. Here is the complete list of masks and constants from 'man 2 stat':

    The following flags are defined for the st_mode field: S_IFMT 0170000 bitmask for the file type bitfields S_IFSOCK 0140000 socket S_IFLNK 0120000 symbolic link S_IFREG 0100000 regular file S_IFBLK 0060000 block device S_IFDIR 0040000 directory S_IFCHR 0020000 character device S_IFIFO 0010000 fifo S_ISUID 0004000 set UID bit S_ISGID 0002000 set GID bit (see below) S_ISVTX 0001000 sticky bit (see below) S_IRWXU 00700 mask for file owner permissions S_IRUSR 00400 owner has read permission S_IWUSR 00200 owner has write permission S_IXUSR 00100 owner has execute permission S_IRWXG 00070 mask for group permissions S_IRGRP 00040 group has read permission S_IWGRP 00020 group has write permission S_IXGRP 00010 group has execute permission S_IRWXO 00007 mask for permissions for others (not in group +) S_IROTH 00004 others have read permission S_IWOTH 00002 others have write permisson S_IXOTH 00001 others have execute permission

    Octal is the popular notation for these, because sets of permissions occupy three bits.

    After Compline,
    Zaxo

      I am wanting to see if my file is a link without having to rerun the stat operator. I saw an note in O'Reilly Perl book that stated that when returning info on a link, stat would return the filetype of the actual file (- , d, etc...). So maybe I should re-phrase my question to: Is there a way to have an algorithm that will tell me what type of file it is without having to check each specific bit. The following code returns a - for the file which is a link in both the $filelink and the $filetype variables.
      # hard code a test link file to check $source_file = "/temp/test/source/dir1/hello1_link.txt"; # define filetype array with potential first bits of mode @ftypes = qw(. p c ? d ? b ? - ? l ? s ? ? ?); $ftypes0 = ''; # Get File Statistics Using Scalar context ($dev,$inode,$mode,$nlink,$uid,$gid,$rdev,$size, $atime,$mtime,$ctime,$blksize,$blocks) = stat($source_file); $perms = $mode & 07777; $octperms = sprintf("%lo", $perms); $filetype = $ftypes[($mode & 0170000)>>12]; $filelink = $ftypes[($mode & 0120000)>>12];
      And while I am admitting how much I don't know, what does the >>12 do in the array reference? Thanks.
        I can answer the last part about the bit shift operator.
        >> 12 takes the number to the left and shifts it 12 bits to the right.
        << 12 would shift it 12 bits to the left.
        In octal there are 3 bits per character shown (is this still called a nibble? Or is that only 4 bits, I don't play in octal that often :)
        So this will bitwise and $mode with 0170000 and then shift it down so that the bottom 4 zero's go away.
        0170000 >> 12 = 017
        Hope this helps!

        You should use the lstat builtin if you don't want to resolve soft links.

        If you use Fcntl qw(:mode); you can get the constants by name. That will be easier to read and remember.

        ++Helter for the other answers.

        After Compline,
        Zaxo

      What does the $mode & 07777 do? Could you explain it in layman's terms. I am not familiar with this type of expression as I am very new to Perl.
        I'm not sure there is a "laymans" terms explanation for this. A single & is a bitwise and. This means it will go through the left and right, compare them bit by bit and the result is determined by the and function:
        src1 src2 dest 0 0 0 0 1 0 1 0 0 1 1 1
        In your example src1 is $mode, src2 is 07777 and dest is $perms. This is mostly used to zero out bits, or mask off portions of bits.
        The bitwise or operator, |, is used to set bits in a bit-string.
        Hope this helped.
Re: Unix File Type with stat
by blm (Hermit) on Sep 10, 2002 at 05:13 UTC

    The 7's in the two numbers seem to indicate a change of base to octal numbers. Unix permissions like 755 etc are quoted as base 8 octal numbers (as opposed to base 10 ie decimal). The rest seems to be a for the purposes of a mask.