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

According to the documentation of the "stat" function we can use Fcntl::S_IFMT($mode) call, where $mode is $stat2.
Results of the Fcntl::S_IFMT($mode) can be bit-anded with the various constants (S_IFREG, S_IFDIR, S_IFLNK, S_IFBLK, S_IFCHR, S_IFIFO, S_IFSOCK, S_IFWHT, S_ENFMT) to determine file type.

So, my question is - why last test returns TRUE?
'/etc/passwd' - is a regular file (not a link), and first two tests confirms this.
But last test says, that '/etc/passwd' is a link.

#!/usr/bin/env perl use strict; use warnings; use Fcntl qw[]; my $path = '/etc/passwd'; my @stat = stat $path or die $!; printf "%s\n", -l $path ? 1 : 0; # 0 - OK, not a link printf "%s\n", Fcntl::S_ISLNK( $stat[2] ) ? 1 : 0; # 0 - OK, not a +link printf "%s\n", Fcntl::S_IFMT( $stat[2] ) & Fcntl::S_IFLNK ? 1 : 0; +# 1 - ERROR __END__

Replies are listed 'Best First'.
Re: Unexpected Fcntl::S_IFLNK behavior
by Corion (Patriarch) on Oct 01, 2018 at 21:10 UTC

    S_IFMT is a bitmask, not a function. You're supposed to use it as:

    printf "%s\n", $stat[2] & Fcntl::S_IFMT & Fcntl::S_IFLNK ? 1 : 0;

    This outputs the expected 0 for me.

      No, you are wrong.

      1. In documentation is clearly wrote, that Fcntl::S_IFMT is a function and should be called as Fcntl::S_IFMT($mode).

      2. If you write:

      printf "%s\n", (stat '/tmp')[2] & Fcntl::S_IFMT & Fcntl::S_IFDIR ? 1 : + 0;
      you will get 0, that is wrong, because "/tmp" is a directory.

        Actually, the S_IFMT can be used as both, a constant and a function, depending on whether you pass in parameters:

        void S_IFMT(...) PREINIT: dXSTARG; PPCODE: PUSHu(items ? (SvUV(ST(0)) & S_IFMT) : S_IFMT);

        It seems to return the AND-ed value from stat():

        #!/usr/bin/env perl use strict; use warnings; use Fcntl qw[]; printf "%08x\n", (stat("/tmp"))[2]; printf "%08x\n", (stat("/etc/passwd"))[2]; printf "%08x\n", Fcntl::S_IFMT( (stat("/tmp"))[2] ); printf "%08x\n", Fcntl::S_IFMT( (stat("/etc/passwd"))[2] ); printf "%08x\n", Fcntl::S_IFMT(); __END__ 000043ff 000081a4 00004000 00008000 0000f000

        I think the intended usage is to compare against identity, just like the GNU usage does, and to use lstat if you want to know about the link instead of the link target:

        #!/usr/bin/env perl use strict; use warnings; use Fcntl qw[]; for my $file ('/tmp/testlink', '/etc/passwd', '/etc') { print "--- $file is link: ", -l $file, "\n"; my $mode = (stat($file))[2]; my $lmode = (lstat($file))[2]; printf "mode: %016b\n", $mode; printf "lmode: %016b\n", $lmode; printf "S_IFMT(): %016b\n", Fcntl::S_IFMT($lmode); printf "S_IFMT: %016b\n", Fcntl::S_IFMT() & $lmode; printf "S_IFMT: %016b\n", Fcntl::S_IFMT(); printf "S_IFLNK: %016b\n", Fcntl::S_IFLNK(); printf "S_IFLNK: %016b\n", (Fcntl::S_IFLNK() & Fcntl::S_IFMT() & $lmo +de) == Fcntl::S_IFLNK() ; printf "S_ISLNK():%016b\n", Fcntl::S_ISLNK($lmode); print "---\n"; } __END__ --- /tmp/testlink is link: 1 mode: 0100001111111111 lmode: 1010000111111111 S_IFMT(): 1010000000000000 S_IFMT: 1010000000000000 S_IFMT: 1111000000000000 S_IFLNK: 1010000000000000 S_IFLNK: 0000000000000001 S_ISLNK():0000000000000001 --- --- /etc/passwd is link: mode: 1000000110100100 lmode: 1000000110100100 S_IFMT(): 1000000000000000 S_IFMT: 1000000000000000 S_IFMT: 1111000000000000 S_IFLNK: 1010000000000000 S_IFLNK: 0000000000000000 S_ISLNK():0000000000000000 --- --- /etc is link: mode: 0100000111101101 lmode: 0100000111101101 S_IFMT(): 0100000000000000 S_IFMT: 0100000000000000 S_IFMT: 1111000000000000 S_IFLNK: 1010000000000000 S_IFLNK: 0000000000000000 S_ISLNK():0000000000000000 ---
Re: Unexpected Fcntl::S_IFLNK behavior
by stevieb (Canon) on Oct 01, 2018 at 20:47 UTC

    It would be prudent to include details as to what you're expecting and why, while providing a description of what the Fcntl:: variables are and do, and their purpose.

    It's not really fair to send everyone looking for un-linked documentation to begin understanding your problem.

    Please provide additional, relevant details.