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

I'm fooling around with giving file system directives in bash versus perl, and I noticed the following:
$rm -rf a; mkdir -m0777 a;ls -ld a drwxrwxrwx 2 hartmann users 48 2006-06-07 20:09 a $rm -rf a; perl -e 'mkdir ('a', 0777)';ls -ld a drwxr-xr-x 2 hartmann users 48 2006-06-07 20:09 a
I would expect the above commands -- make directory a with all permissions granted to everyone -- to give the same result.

But in mkdir from perl, group and "all" are missing the write permissions.

I am curious about this and wonder if there is a rationale for the discrepancy.

Clarification welcome!

Replies are listed 'Best First'.
Re: Why does unix mkdir and perl mkdir behave differently?
by Fletch (Bishop) on Jun 07, 2006 at 18:25 UTC

    The -m argument to the (presumably) GNU mkdir command makes it set the permissions disregarding the process' umask. The Perl mkdir call is just calling the bare mkdir(2) system call which honours the umask. If you don't want the umask to affect things either explicitly set it to a known value or call chmod yourself after making the directory.

    Update: And with strace you can see the later is exactly what the GNU mkdir is doing underneath the hood:

    $ strace -e chmod,mkdir mkdir -m0777 spoo mkdir("spoo", 0777) = 0 chmod("spoo", 0777) = 0
Re: Why does unix mkdir and perl mkdir behave differently?
by chargrill (Parson) on Jun 07, 2006 at 18:24 UTC

    According to the documentation,

    Creates the directory specified by FILENAME, with permi +ssions specified by MASK (as modified by "umask"). If it succ +eeds it returns true, otherwise it returns false and sets $! (e +rrno). If omitted, MASK defaults to 0777. In general, it is better to create directories with per +missive MASK, and let the user modify that with their "umask", +than it is to supply a restrictive MASK and give the user no wa +y to be more permissive. The exceptions to this rule are when +the file or directory should be kept private (mail files, for in +stance). The perlfunc(1) entry on "umask" discusses the choice o +f MASK in more detail.

    That's all well and good, but on my system, my default umask is 022, so your code still creates a directory as drwxr-xr-x for me. The follwoing seems to do what you want:

    perl -e "umask 000; mkdir 'a', 0777";ls -ld a
    Update:

    I think the docs could be a it more clear that even given a mask for creating directories, mkdir still honors the users umask. - OR I could try READING what I just posted ;)



    --chargrill
    $,=42;for(34,0,-3,9,-11,11,-17,7,-5){$*.=pack'c'=>$,+=$_}for(reverse s +plit//=>$* ){$%++?$ %%2?push@C,$_,$":push@c,$_,$":(push@C,$_,$")&&push@c,$"}$C[$# +C]=$/;($#C >$#c)?($ c=\@C)&&($ C=\@c):($ c=\@c)&&($C=\@C);$%=$|;for(@$c){print$_^ +$$C[$%++]}

      Erm, it says "with permissions specified by MASK (as modified by "umask")"; can't get much more clear than that.

      Was wondering if I could request that posts are PREVIEWED before POSTING.. having a block of text that is wrapping is not easy to read.. :(
Re: Why does unix mkdir and perl mkdir behave differently?
by Joost (Canon) on Jun 07, 2006 at 18:27 UTC
Re: Why does unix mkdir and perl mkdir behave differently?
by ambrus (Abbot) on Jun 07, 2006 at 21:31 UTC

    Perl's mkdir is an interface to the mkdir function, not the unix mkdir program which is a bit more sophisticated.

    This is similar to how other calls work: you can type ln -s foo bar to command line if bar is a directory and it will act like ln -s foo bar/foo, but you can't do the same with the symlink call; rm will ask you if you want to remove a read-only file, while the unlink call won't; mv will move across file systems while rename won't; etc. Only this time the name of the utility is exactly the same as that of the system call.

    (Note also that GNU coreutils has a few newer programs that correspond more to the system calls than the traditional utilities: link instead of ln, unlink instead of rm. A bit similar in spirit are stat and readlink instead of ls -l.)

    Update: To clarify, the unix system call mkdir should behave this way, modifying the permission of the directory with umask, so the perl mkdir function behaves correctly. If you want to force specific permissions on the new directory, you have to call chmod after mkdir. Modifying the umask temporarily might not be enough if you want to control the extra bits (eg. setgid, sticky), as, depending on the system, these may get initialized independently of the umask and the permission value you pass to mkdir. For example, in linux, you typically need chmod to make a directory setgid.

Re: Why does unix mkdir and perl mkdir behave differently?
by swampyankee (Parson) on Jun 07, 2006 at 18:35 UTC

    I think what's happening is that the mask argument to mkdir is interacting with the value of umask. To quote:

    The permission (or ``mode'') values you pass mkdir or sysopen are modified by your umask, so even if you tell sysopen to create a file with permissions 0777, if your umask is 0022 then the file will actually be created with permissions 0755.

    emc

    e(π√−1) = −1