in reply to Unexpected Fcntl::S_IFLNK behavior

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.

Replies are listed 'Best First'.
Re^2: Unexpected Fcntl::S_IFLNK behavior
by zdm (Beadle) on Oct 01, 2018 at 21:38 UTC
    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 ---
        Thank you.