Beefy Boxes and Bandwidth Generously Provided by pair Networks
Perl: the Markov chain saw
 
PerlMonks  

Re: POSIX::S_ISDIR() with $stat->mode values from Windows vs. Linux

by isync (Hermit)
on Oct 05, 2009 at 18:31 UTC ( [id://799315]=note: print w/replies, xml ) Need Help??


in reply to POSIX::S_ISDIR() with $stat->mode values from Windows vs. Linux

jakobi's comment, I think, leads into the very core of the problem. The difference between a numeric, a string and octals. And the fact that I still haven't quite figured out the logics behind a bitmask, bit operators and the like.

A bit of pseudo code to illustrate my script, so someone who kwows this stuff better than me can tell me where I need to throw in the oct() function or so to make it work again:
  1. server-side script does a stat()
  2. server-side script returns a HTTP::Response with content in the form "$name\t$size\t$mode\t$nlink\t$ctime\t$atime\t$mtime"
  3. client-side script receives the response content as a string
  4. client-side script does @stat  = split(/\t/, $stat); on the string
  5. client-side script does if(POSIX::S_ISDIR(int($stat[1]))){ ... } # int() to make sure its numeric, but something got lost here

5. worked in a test-setup where "server-side" was on Windows and "client-side" was on Windows
5. broke when I migrated the "server-side" to a Debian machine.
(how to encode/decode $mode to keep it intact while represented as a string?)

BTW: man (2) stat is full of insight... ;-)

Replies are listed 'Best First'.
Re^2: POSIX::S_ISDIR() ... octal strings, bit manipulations
by Sandy (Curate) on Oct 05, 2009 at 19:19 UTC
    my $d = "16895"; my $f = "33206"; my $od = sprintf("%5o",$d); my $of = sprintf("%5o",$f); print "$d->$od\n$f->$of\n"; my $d = "16877"; my $f = "33188"; my $od = sprintf("%5o",$d); my $of = sprintf("%5o",$f); print "$d->$od\n$f->$of\n"; # get the three lowest bits (use the INTEGER value for this, not the o +ctal string!) my $l3b = $d & 7; # 0000111 in binary, or '7' in octal and in dec print "lowest three bits of octal $od is $l3b\n"; # get the three bits starting at bit 4 (111000 in bin, 70 in oct, 56 d +ec) my $l43b = $d & oct(70); # still 6 bits though, $l43b = $l43b >> 3; print "$od and oct(70) shifted 3 bits to the right = ",sprintf("%o",$l +43b)," in octal\n";
    gives
    16895->40777 33206->100666 16877->40755 33188->100644 lowest three bits of octal 40755 is 5 40755 and oct(70) shifted 3 bits to the right = 5 in octal
Re^2: POSIX::S_ISDIR() with $stat->mode values from Windows vs. Linux
by jakobi (Pilgrim) on Oct 05, 2009 at 19:31 UTC

    Ok, I'll bite

    First of all, I don't see any need for oct(). This is a bitfield - so you might want to do a perl -e 'printf "0%o\n", 16895' for human consumption. And if you ever see that on Unix and it isn't called tmp, you'll probably also want to give the culprit a lecture about security risks. The readable form of this number is 040777, with 777 being the permission bits of read/write/executable for all of user, group and other (read maybe as 040ugo:) ).

    Now let's peek at the includes, pretending that the 040 wasn't an obvious hint to us for the encoding of the directory file type.

    Might be a useful trick of the trade for use with more difficult future questions in situations where Perl offers less or no suitable abstractions or you need some background to properly make use of them.

    $ grep -lri mode_t /usr/include $ # as usual, do sceptically eyeball sys and linux, $ # but for now, this sounds like a hit: $ less /usr/include/bits/stat.h /* Encoding of the file mode. */ #define __S_IFMT 0170000 /* These bits determine file type. +*/ /* File types. */ #define __S_IFDIR 0040000 /* Directory. */ #define __S_IFCHR 0020000 /* Character device. */ #define __S_IFBLK 0060000 /* Block device. */ #define __S_IFREG 0100000 /* Regular file. */ #define __S_IFIFO 0010000 /* FIFO. */ #define __S_IFLNK 0120000 /* Symbolic link. */ #define __S_IFSOCK 0140000 /* Socket. */ /* POSIX.1b objects. Note that these macros always evaluate to zero. + But they do it by enforcing the correct use of the macros. */ #define __S_TYPEISMQ(buf) ((buf)->st_mode - (buf)->st_mode) #define __S_TYPEISSEM(buf) ((buf)->st_mode - (buf)->st_mode) #define __S_TYPEISSHM(buf) ((buf)->st_mode - (buf)->st_mode) /* Protection bits. */ #define __S_ISUID 04000 /* Set user ID on execution. */ #define __S_ISGID 02000 /* Set group ID on execution. */ #define __S_ISVTX 01000 /* Save swapped text after use (stick +y). */ #define __S_IREAD 0400 /* Read by owner. */ #define __S_IWRITE 0200 /* Write by owner. */ #define __S_IEXEC 0100 /* Execute by owner. */ # strange - this file doesn't define access macros for group/other..

    The numbers above are octal numbers, for improved readability, as hinted at by the leading 0.

    So you say in Perl $mode & 0777 to restrict the $mode to the actual file permissions (cf. chmod arguments!). Say $mode & 07 to check the access of nobody (but remember in the background that there's also filesystem specific stuff like ACL and Extended Attributes, which can modify the traditional perms; hopefully somebody alreade made a module for checking on these headaches :))

    To test for a directory w/o POSIX, but just boolean operators directly. Which is just what the minimal wrapping by the POSIX module does:

    warn "a dir\n" if (stat ".")[2] & 040000 == 040000

    with 040000 being __S_IFDIR from the includes above. Recognized POSIX::S_IFDIR?

    I think that should be enough about background and boolean masking. Note that instead of and, or, exor you can also left or right-shift the bits (man perlop: search for &, |, ^, <<, >>).

    AFAIS, the missing bits / misunderstandings were:

    • not printing the values in octal for readability during debugging,
    • possibly explicit testing of equality of modes as is, without masking the irrelevant bits
    • S_IFDIR considers exactly 1 bit, both on Windows and in the Linux VFS. There is exactly one type of directory on both platforms for all filesystems :). excluding of the more interesting non-standard abuses of FUSE for now.

    If possible however, try the normal perl tests like -d as already suggested.

    cu
    Peter

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: note [id://799315]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others exploiting the Monastery: (5)
As of 2024-03-28 19:40 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found