Beefy Boxes and Bandwidth Generously Provided by pair Networks
The stupid question is the question not asked

Testing for group or world writable files

by neilwatson (Priest)
on Jul 07, 2015 at 01:02 UTC ( #1133485=perlquestion: print w/replies, xml ) Need Help??
neilwatson has asked for the wisdom of the Perl Monks concerning the following question:


I want to test if a file is writable by the group or world. What I tried is below, but test three fails unexpectedly

#!/usr/bin/perl use strict; use warnings; use Data::Dumper; use feature 'say'; use Test::More; use File::stat; my $file = $ARGV[0]; my $sb = stat( $file ); my $mode = $sb->mode & 0777; warn "mode of [$file] is [$mode]"; ok( -O $file, "File owned by real uid" ); ok( -f $file, "File is a plain file" ); ok( ! $mode & 022, "File is not group or world writable" ); done_testing; # Results in: mode of [/etc/passwd] is [420] at ./ line 14. not ok 1 - File owned by real uid # Failed test 'File owned by real uid' # at ./ line 16. ok 2 - File is a plain file not ok 3 - File is not group or world writable # Failed test 'File is not group or world writable' # at ./ line 18. 1..3 # Looks like you failed 2 tests of 3.

Neil Watson

Replies are listed 'Best First'.
Re: Testing for group or world writable files
by Loops (Curate) on Jul 07, 2015 at 01:34 UTC
    Seems you need the parenthesis for precedence:
    ok( ! ($mode & 022), "File is not group or world writable" );
    Works here.
      I've just seen a presentation on Coccinelle, this kind of error was quite common in the Linux kernel. See here.
      لսႽ ᥲᥒ⚪⟊Ⴙᘓᖇ Ꮅᘓᖇ⎱ Ⴙᥲ𝇋ƙᘓᖇ
Re: Testing for group or world writable files
by stevieb (Abbot) on Jul 07, 2015 at 01:28 UTC

    Here's one non-scientific way to check:

    #!/usr/bin/perl use warnings; use strict; use Test::More; my $file = 'file.txt'; my $perms = sprintf("%o", (stat $file)[2] & 0777); my ($u, $g, $w) = split //, $perms; my @writable = qw(2 3 6 7); ok (!(grep /$g/, @writable), "File is not group writable"); ok (!(grep /$w/, @writable), "File is not world writable");


Re: Testing for group or world writable files
by kcott (Chancellor) on Jul 07, 2015 at 13:48 UTC

    G'day Neil,

    I see answers identifying a precedence problem. Rather than using the ! operator and adding (multiple levels of) parentheses, you can just use the low-precedence equivalent: not (see "perlop: Operator Precedence and Associativity"). There's also low-precedence and, or and xor. I find these operators make the code easier to read than using parentheses: you, of course, may have a different preference.

    Instead of using Test::More's ok() function (and, where necessary, negating the test), consider using the is() and isnt() functions. This (at least in the case of your posted code) circumvents the precedence issue entirely; it also aligns the test function with the test description. Here's an example roughly based on your code:

    #!/usr/bin/env perl use strict; use warnings; use Test::More tests => 4; my $mode = (stat $0)[2]; isnt(-d $0, 1, "This script isn't a directory."); is( -O $0, 1, "This script is owned by real uid."); isnt($mode & 020, 020, "This script isn't group writable."); isnt($mode & 002, 002, "This script isn't world writable.");

    [Note that I've used the core (builtin) stat function. File::stat, by default, overrides this.]


    1..4 ok 1 - This script isn't a directory. ok 2 - This script is owned by real uid. ok 3 - This script isn't group writable. ok 4 - This script isn't world writable.

    Update: While my intent was to compare ok() with is() and isnt(), which I believed I achieved, I did notice a bug in the example code. I've fixed the code; retested; and posted the new code and output. The offending line was:

    isnt((stat $0)[2] & 022, 022, "This script isn't group or world writab +le.");

    Update 2: My bug fix (from the initial update) left the code a bit messy. I've tidied that up. Now just one call to stat with the result stored in $mode. Retested successfully; output unchanged; new code posted.

    -- Ken

Re: Testing for group or world writable files
by Anonymous Monk on Jul 07, 2015 at 01:52 UTC

    I see, another way to the answer is via Basic debugging checklist

    $ perl -MO=Deparse,-p ok( ! $mode & 022, "File is not group or world writable" ); ^Z ok(((!$mode) & 18), 'File is not group or world writable'); - syntax OK

Log In?

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://1133485]
Approved by toolic
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others perusing the Monastery: (5)
As of 2018-12-19 02:09 GMT
Find Nodes?
    Voting Booth?
    How many stories does it take before you've heard them all?

    Results (83 votes). Check out past polls.