Beefy Boxes and Bandwidth Generously Provided by pair Networks
There's more than one way to do things
 
PerlMonks  

mkdir with variable mask

by kreetrapper (Scribe)
on Jan 26, 2009 at 14:19 UTC ( [id://738934]=perlquestion: print w/replies, xml ) Need Help??

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

Hi all,

I'm still new to Perl so please don't laugh if this is a dumb question.

I want to create a directory and give it the same permissions as its parent. This does not seem to happen by default, so my idea was to read out the parent folder's permissions with stat and supply these to mkdir. My code looks like this
my $dir = "/home/me/perl-stuff/"; my $mode_long = (stat($dir))[2]; my $mode = sprintf("%o", ($mode_long&07777)); my $oct_mode = '0'.$mode; my $oct = oct($oct_mode); $dir .= "test"; my $x = umask; umask 0000; mkdir ($dir,$oct); umask $x;
This works and has the desired effect, but I can't shake the feeling that there must be an easier way to do this. Or at least a shorter one. Obviously handling these octal numbers keeps confusing me.

thanks,
Alex

Replies are listed 'Best First'.
Re: mkdir with variable mask
by moritz (Cardinal) on Jan 26, 2009 at 14:28 UTC
    You don't have to pass a string to umask that represents an octal number - anything that's stored as a number, or can be converted to a number, is fine.
    umask 0777; umask 511; # same, with decimal notation - but slightly confusing my $u = 0777; $u &= $other_number; umask $u; # also works
Re: mkdir with variable mask
by linuxer (Curate) on Jan 26, 2009 at 14:31 UTC

    Well, I think, you could consider to use chmod directly after successful creation of the new directory.

    untested quickshot of my thoughts:

    #! /usr/bin/perl use strict; use warnings; # added: use File::Spec::Functions qw( catdir ); my $dir = '/home/me/perl-stuff/"; my $mode = (stat $dir)[2]; # better use File::Spec::catfile #$dir .= 'testdir'; $dir = catdir( $dir, 'testdir' ); mkdir( $dir, $mode ) or die "$!\n"; # update2: $mode added chmod( $mode, $dir ) or die "$!\n";

    updates

    1. code example updated, because I did some testing.
    2. Considered ikegami's reply...
    3. strike-tags adjusted
    4. catfile replaced with catdir; thanks kreetrapper
      Well, I think, you could consider to use chmod directly after successful creation of the new directory


      Yes, that seems to be the better option. Thanks.

      At the conception stage I thought, that by giving mkdir the mode directly I could save one command. But that was before I learned about 'umask' and it all got more and more complicated.

      And, thanks for the pointer to catfile. I will use this in the future.

      BTW: What exactly is umask for? To me it seems like my system tries to tell me how I should set my permissions - which I don't really like. And it has no real point as a security measure if you can just reset the value or even chmod the resulting dir/file any way you like.

      Alex

        To me it seems like my system tries to tell me how I should set my permissions - which I don't really like.

        Other way around. It's you telling the system how to limit permissions so you don't go around creating world accessible files everywhere. There's a system default, but you can override it in your login script.

        To add to what ikegami said...

        Using umask plus the permission parameter to mkdir allows you to further avoid some potential race conditions. Along with executable stacks being exploited with buffer overflows, race conditions have been, at least by my memory, a significant contributor to security exploits.

        It may be worth the couple of extra minutes to code the umask stuff and skip the chmod, especially if you do not have a full handle on how your code may be used in the future.

        --MidLifeXis

Re: mkdir with variable mask
by ctilmes (Vicar) on Jan 26, 2009 at 15:46 UTC
    I want to create a directory and give it the same permissions as its parent.

    Just to go back a step... Why do you want to give it the same permissions as its parent?

    Not to say you don't have a good reason, but in general things just work as they ought if you just make the directory and let the OS follow the user's umask and make the directory with defaults.

    By explicitly setting permissions, you are often overriding things that the OS and user have set.

      Why do you want to give it the same permissions as its parent?
      Honestly, now that you mention it, I don't really know. Probably I just saw that you could set the permissions with mkdir and thought that I had to. Which is, of course, nonsene. I had a very strange day yesterday anyway, so I just blame my general dizziness for this. ;-)

      Thank you all for your helpful insights. I am not experienced enough at the moment to know what exactly race conditions are, but it seems like a good idea to avoid them, so I will keep that in mind.

      One more question though, regarding linuxer's answer:

      I looked at File::Spec and I wondered whether there is a reason why you are using catfile instead of catdir.

      Alex

        Good point. until now, I used catfile more often than catdir, so it came faster to my mind.

        I will correct my codes accordingly. catdir should be used here.

Re: mkdir with variable mask
by ELISHEVA (Prior) on Jan 26, 2009 at 19:41 UTC

    If your main concern is securing a file, there is an easier way - set the sticky, setgid, and setuid bits on the directory. While this doesn't insure that the files have the exact same permissions, it does insure that (a) all files created in the directory will have the same group and owner as the directory (b) the files cannot be renamed or deleted except by the owner, i.e. the directory owner. This should go a long way to securing the files and avoiding race conditions while you clean up the permissions - especially if the user owning the directory is controlled by your script.

    To setup the directory, add 7000 to the normal three digit permissions. (1000=sticky bit, 2000=setgid, 4000=setuid).

    Another alternative you might want to consider is the *nix install command. This does a better job of letting you create a file with specific permissions whilst avoiding race conditions that might jeopardize security

    For more information, see

    Best of luck, beth

    P.S. I'm assuming, of course, that you are working on a *nix system. These commands only work on the *nixes. (WinDos has its own funky logic for permissions and inheritance).

Re: mkdir with variable mask
by linuxer (Curate) on Jan 26, 2009 at 17:07 UTC

    After MidLifeXis mentioned the race condition which is unfortunately included in my previous solution, I would like to present another solution, which uses umask.

    What about this solution?

    #!/usr/bin/perl # vi:ts=4 sw=4 et: use strict; use warnings; use File::Spec::Functions qw( catdir ); my $dir = '/home/me/perl-stuff'; # obtain type and permissions and strip off type information; see: per +ldoc -f stat my $mask = ( stat $dir )[2] & 07777; # path of new directory $dir = catdir( $dir, 'new_dir' ); # set new calculated umask and store old value; see: perldoc -f umask my $old_umask = umask 0777-$mask; # create directory; see: perldoc -f mkdir mkdir( $dir ) or die $!; # restore old umask value umask $old_umask; __END__
    <update>

Log In?
Username:
Password:

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

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

    No recent polls found