1b8851fccSafresh1use strict; 2b8851fccSafresh1use Test::More; 3b8851fccSafresh1use Config; 42e109fb9Safresh1use lib './t'; 52e109fb9Safresh1use FilePathTest qw( 62e109fb9Safresh1 _run_for_warning 72e109fb9Safresh1); 8b8851fccSafresh1use File::Path qw(rmtree mkpath make_path remove_tree); 9b8851fccSafresh1use File::Spec::Functions; 10b8851fccSafresh1 11b8851fccSafresh1 12b8851fccSafresh1my $prereq = prereq(); 13b8851fccSafresh1plan skip_all => $prereq if defined $prereq; 142e109fb9Safresh1plan tests => 11; 15b8851fccSafresh1 16b8851fccSafresh1my $pwent = max_u(); 17b8851fccSafresh1my $grent = max_g(); 18b8851fccSafresh1my ( $max_uid, $max_user ) = @{ $pwent }; 19b8851fccSafresh1my ( $max_gid, $max_group ) = @{ $grent }; 20b8851fccSafresh1 21b8851fccSafresh1my $tmp_base = catdir( 22b8851fccSafresh1 curdir(), 23b8851fccSafresh1 sprintf( 'test-%x-%x-%x', time, $$, rand(99999) ), 24b8851fccSafresh1); 25b8851fccSafresh1 26b8851fccSafresh1# invent some names 27b8851fccSafresh1my @dir = ( 28b8851fccSafresh1 catdir($tmp_base, qw(a b)), 29b8851fccSafresh1 catdir($tmp_base, qw(a c)), 30b8851fccSafresh1 catdir($tmp_base, qw(z b)), 31b8851fccSafresh1 catdir($tmp_base, qw(z c)), 32b8851fccSafresh1); 33b8851fccSafresh1 34b8851fccSafresh1# create them 35b8851fccSafresh1my @created = mkpath([@dir]); 36b8851fccSafresh1 37b8851fccSafresh1my $dir; 38b8851fccSafresh1my $dir2; 39b8851fccSafresh1 40b8851fccSafresh1my $dir_stem = $dir = catdir($tmp_base, 'owned-by'); 41b8851fccSafresh1 42b8851fccSafresh1$dir = catdir($dir_stem, 'aaa'); 43b8851fccSafresh1@created = make_path($dir, {owner => $max_user}); 44b8851fccSafresh1is(scalar(@created), 2, "created a directory owned by $max_user..."); 45b8851fccSafresh1 46b8851fccSafresh1my $dir_uid = (stat $created[0])[4]; 47b8851fccSafresh1is($dir_uid, $max_uid, "... owned by $max_uid"); 48b8851fccSafresh1 49b8851fccSafresh1$dir = catdir($dir_stem, 'aab'); 50b8851fccSafresh1@created = make_path($dir, {group => $max_group}); 51b8851fccSafresh1is(scalar(@created), 1, "created a directory owned by group $max_group..."); 52b8851fccSafresh1 53b8851fccSafresh1my $dir_gid = (stat $created[0])[5]; 54b8851fccSafresh1is($dir_gid, $max_gid, "... owned by group $max_gid"); 55b8851fccSafresh1 56b8851fccSafresh1$dir = catdir($dir_stem, 'aac'); 57b8851fccSafresh1@created = make_path( $dir, { user => $max_user, 58b8851fccSafresh1 group => $max_group}); 59b8851fccSafresh1is(scalar(@created), 1, "created a directory owned by $max_user:$max_group..."); 60b8851fccSafresh1 61b8851fccSafresh1($dir_uid, $dir_gid) = (stat $created[0])[4,5]; 62b8851fccSafresh1is($dir_uid, $max_uid, "... owned by $max_uid"); 63b8851fccSafresh1is($dir_gid, $max_gid, "... owned by group $max_gid"); 64b8851fccSafresh1 652e109fb9Safresh1{ 66b8851fccSafresh1 # invent a user and group that don't exist 67*b46d8ef2Safresh1 my $phony_user = get_phony_user(); 68*b46d8ef2Safresh1 my $phony_group = get_phony_group(); 69b8851fccSafresh1 70b8851fccSafresh1 $dir = catdir($dir_stem, 'aad'); 712e109fb9Safresh1 my $rv = _run_for_warning( sub { 722e109fb9Safresh1 make_path( 732e109fb9Safresh1 $dir, 74*b46d8ef2Safresh1 { user => $phony_user, group => $phony_group } 752e109fb9Safresh1 ) 762e109fb9Safresh1 } ); 77b8851fccSafresh1 like( $rv, 78*b46d8ef2Safresh1 qr{unable to map $phony_user to a uid, ownership not changed:}s, 79*b46d8ef2Safresh1 "created a directory not owned by $phony_user:$phony_group...", 80b8851fccSafresh1 ); 812e109fb9Safresh1 like( $rv, 82*b46d8ef2Safresh1 qr{unable to map $phony_group to a gid, group ownership not changed:}s, 83*b46d8ef2Safresh1 "created a directory not owned by $phony_user:$phony_group...", 842e109fb9Safresh1 ); 852e109fb9Safresh1} 862e109fb9Safresh1 872e109fb9Safresh1{ 882e109fb9Safresh1 # cleanup 892e109fb9Safresh1 my $x; 902e109fb9Safresh1 my $opts = { error => \$x }; 912e109fb9Safresh1 remove_tree($tmp_base, $opts); 922e109fb9Safresh1 ok(! -d $tmp_base, "directory '$tmp_base' removed, as expected"); 932e109fb9Safresh1 is(scalar(@{$x}), 0, "no error messages using remove_tree() with \$opts"); 94b8851fccSafresh1} 95b8851fccSafresh1 96b8851fccSafresh1sub max_u { 97b8851fccSafresh1 # find the highest uid ('nobody' or similar) 98b8851fccSafresh1 my $max_uid = 0; 99b8851fccSafresh1 my $max_user = undef; 100b8851fccSafresh1 while (my @u = getpwent()) { 101b8851fccSafresh1 if ($max_uid < $u[2]) { 102b8851fccSafresh1 $max_uid = $u[2]; 103b8851fccSafresh1 $max_user = $u[0]; 104b8851fccSafresh1 } 105b8851fccSafresh1 } 106b8851fccSafresh1 setpwent(); # in case we want to run again later 107b8851fccSafresh1 return [ $max_uid, $max_user ]; 108b8851fccSafresh1} 109b8851fccSafresh1 110b8851fccSafresh1sub max_g { 111b8851fccSafresh1 # find the highest gid ('nogroup' or similar) 112b8851fccSafresh1 my $max_gid = 0; 113b8851fccSafresh1 my $max_group = undef; 114b8851fccSafresh1 while ( my @g = getgrent() ) { 115b8851fccSafresh1 if ($max_gid < $g[2]) { 116b8851fccSafresh1 $max_gid = $g[2]; 117b8851fccSafresh1 $max_group = $g[0]; 118b8851fccSafresh1 } 119b8851fccSafresh1 } 120b8851fccSafresh1 setgrent(); # in case we want to run again later 121b8851fccSafresh1 return [ $max_gid, $max_group ]; 122b8851fccSafresh1} 123b8851fccSafresh1 124b8851fccSafresh1sub prereq { 125b8851fccSafresh1 return "getpwent() not implemented on $^O" unless $Config{d_getpwent}; 126b8851fccSafresh1 return "getgrent() not implemented on $^O" unless $Config{d_getgrent}; 127b8851fccSafresh1 return "not running as root" unless $< == 0; 128b8851fccSafresh1 return "darwin's nobody and nogroup are -1 or -2" if $^O eq 'darwin'; 129b8851fccSafresh1 130b8851fccSafresh1 my $pwent = max_u(); 131b8851fccSafresh1 my $grent = max_g(); 132b8851fccSafresh1 my ( $max_uid, $max_user ) = @{ $pwent }; 133b8851fccSafresh1 my ( $max_gid, $max_group ) = @{ $grent }; 134b8851fccSafresh1 135b8851fccSafresh1 return "getpwent() appears to be insane" unless $max_uid > 0; 136b8851fccSafresh1 return "getgrent() appears to be insane" unless $max_gid > 0; 137b8851fccSafresh1 return undef; 138b8851fccSafresh1} 139*b46d8ef2Safresh1 140*b46d8ef2Safresh1sub get_phony_user { 141*b46d8ef2Safresh1 return "getpwent() not implemented on $^O" unless $Config{d_getpwent}; 142*b46d8ef2Safresh1 return "not running as root" unless $< == 0; 143*b46d8ef2Safresh1 my %real_users = (); 144*b46d8ef2Safresh1 while(my @a=getpwent()) { 145*b46d8ef2Safresh1 $real_users{$a[0]}++; 146*b46d8ef2Safresh1 } 147*b46d8ef2Safresh1 my $phony_stem = 'phonyuser'; 148*b46d8ef2Safresh1 my $phony = ''; 149*b46d8ef2Safresh1 do { $phony = $phony_stem . int(rand(10000)); } until (! $real_users{$phony}); 150*b46d8ef2Safresh1 return $phony; 151*b46d8ef2Safresh1} 152*b46d8ef2Safresh1 153*b46d8ef2Safresh1sub get_phony_group { 154*b46d8ef2Safresh1 return "getgrent() not implemented on $^O" unless $Config{d_getgrent}; 155*b46d8ef2Safresh1 return "not running as root" unless $< == 0; 156*b46d8ef2Safresh1 my %real_groups = (); 157*b46d8ef2Safresh1 while(my @a=getgrent()) { 158*b46d8ef2Safresh1 $real_groups{$a[0]}++; 159*b46d8ef2Safresh1 } 160*b46d8ef2Safresh1 my $phony_stem = 'phonygroup'; 161*b46d8ef2Safresh1 my $phony = ''; 162*b46d8ef2Safresh1 do { $phony = $phony_stem . int(rand(10000)); } until (! $real_groups{$phony}); 163*b46d8ef2Safresh1 return $phony; 164*b46d8ef2Safresh1} 165*b46d8ef2Safresh1 166