| Filename | /usr/lib64/perl5/vendor_perl/5.16.0/File/Path.pm |
| Statements | Executed 26 statements in 14.8ms |
| Calls | P | F | Exclusive Time |
Inclusive Time |
Subroutine |
|---|---|---|---|---|---|
| 1 | 1 | 1 | 99µs | 99µs | File::Path::BEGIN@3 |
| 1 | 1 | 1 | 63µs | 205µs | File::Path::BEGIN@329 |
| 1 | 1 | 1 | 53µs | 150µs | File::Path::BEGIN@4 |
| 1 | 1 | 1 | 50µs | 217µs | File::Path::BEGIN@6 |
| 1 | 1 | 1 | 49µs | 410µs | File::Path::BEGIN@19 |
| 1 | 1 | 1 | 24µs | 24µs | File::Path::BEGIN@7 |
| 1 | 1 | 1 | 22µs | 22µs | File::Path::BEGIN@18 |
| 1 | 1 | 1 | 21µs | 21µs | File::Path::BEGIN@10 |
| 1 | 1 | 1 | 20µs | 20µs | File::Path::BEGIN@8 |
| 0 | 0 | 0 | 0s | 0s | File::Path::_carp |
| 0 | 0 | 0 | 0s | 0s | File::Path::_croak |
| 0 | 0 | 0 | 0s | 0s | File::Path::_error |
| 0 | 0 | 0 | 0s | 0s | File::Path::_is_subdir |
| 0 | 0 | 0 | 0s | 0s | File::Path::_mkpath |
| 0 | 0 | 0 | 0s | 0s | File::Path::_rmtree |
| 0 | 0 | 0 | 0s | 0s | File::Path::_slash_lc |
| 0 | 0 | 0 | 0s | 0s | File::Path::make_path |
| 0 | 0 | 0 | 0s | 0s | File::Path::mkpath |
| 0 | 0 | 0 | 0s | 0s | File::Path::remove_tree |
| 0 | 0 | 0 | 0s | 0s | File::Path::rmtree |
| Line | State ments |
Time on line |
Calls | Time in subs |
Code |
|---|---|---|---|---|---|
| 1 | package File::Path; | ||||
| 2 | |||||
| 3 | 2 | 296µs | 1 | 99µs | # spent 99µs within File::Path::BEGIN@3 which was called:
# once (99µs+0s) by File::Temp::BEGIN@145 at line 3 # spent 99µs making 1 call to File::Path::BEGIN@3 |
| 4 | 2 | 156µs | 2 | 246µs | # spent 150µs (53+97) within File::Path::BEGIN@4 which was called:
# once (53µs+97µs) by File::Temp::BEGIN@145 at line 4 # spent 150µs making 1 call to File::Path::BEGIN@4
# spent 97µs making 1 call to strict::import |
| 5 | |||||
| 6 | 2 | 144µs | 2 | 384µs | # spent 217µs (50+167) within File::Path::BEGIN@6 which was called:
# once (50µs+167µs) by File::Temp::BEGIN@145 at line 6 # spent 217µs making 1 call to File::Path::BEGIN@6
# spent 167µs making 1 call to Exporter::import |
| 7 | 2 | 113µs | 1 | 24µs | # spent 24µs within File::Path::BEGIN@7 which was called:
# once (24µs+0s) by File::Temp::BEGIN@145 at line 7 # spent 24µs making 1 call to File::Path::BEGIN@7 |
| 8 | 2 | 195µs | 1 | 20µs | # spent 20µs within File::Path::BEGIN@8 which was called:
# once (20µs+0s) by File::Temp::BEGIN@145 at line 8 # spent 20µs making 1 call to File::Path::BEGIN@8 |
| 9 | |||||
| 10 | # spent 21µs within File::Path::BEGIN@10 which was called:
# once (21µs+0s) by File::Temp::BEGIN@145 at line 16 | ||||
| 11 | 1 | 44µs | if ($] < 5.006) { | ||
| 12 | # can't say 'opendir my $dh, $dirname' | ||||
| 13 | # need to initialise $dh | ||||
| 14 | eval "use Symbol"; | ||||
| 15 | } | ||||
| 16 | 1 | 94µs | 1 | 21µs | } # spent 21µs making 1 call to File::Path::BEGIN@10 |
| 17 | |||||
| 18 | 2 | 159µs | 1 | 22µs | # spent 22µs within File::Path::BEGIN@18 which was called:
# once (22µs+0s) by File::Temp::BEGIN@145 at line 18 # spent 22µs making 1 call to File::Path::BEGIN@18 |
| 19 | 2 | 9.53ms | 2 | 771µs | # spent 410µs (49+361) within File::Path::BEGIN@19 which was called:
# once (49µs+361µs) by File::Temp::BEGIN@145 at line 19 # spent 410µs making 1 call to File::Path::BEGIN@19
# spent 361µs making 1 call to vars::import |
| 20 | 1 | 5µs | $VERSION = '2.09'; | ||
| 21 | 1 | 36µs | @ISA = qw(Exporter); | ||
| 22 | 1 | 6µs | @EXPORT = qw(mkpath rmtree); | ||
| 23 | 1 | 4µs | @EXPORT_OK = qw(make_path remove_tree); | ||
| 24 | |||||
| 25 | 1 | 9µs | my $Is_VMS = $^O eq 'VMS'; | ||
| 26 | 1 | 5µs | my $Is_MacOS = $^O eq 'MacOS'; | ||
| 27 | |||||
| 28 | # These OSes complain if you want to remove a file that you have no | ||||
| 29 | # write permission to: | ||||
| 30 | 1 | 14µs | my $Force_Writeable = grep {$^O eq $_} qw(amigaos dos epoc MSWin32 MacOS os2); | ||
| 31 | |||||
| 32 | # Unix-like systems need to stat each directory in order to detect | ||||
| 33 | # race condition. MS-Windows is immune to this particular attack. | ||||
| 34 | 1 | 4µs | my $Need_Stat_Check = !($^O eq 'MSWin32'); | ||
| 35 | |||||
| 36 | sub _carp { | ||||
| 37 | require Carp; | ||||
| 38 | goto &Carp::carp; | ||||
| 39 | } | ||||
| 40 | |||||
| 41 | sub _croak { | ||||
| 42 | require Carp; | ||||
| 43 | goto &Carp::croak; | ||||
| 44 | } | ||||
| 45 | |||||
| 46 | sub _error { | ||||
| 47 | my $arg = shift; | ||||
| 48 | my $message = shift; | ||||
| 49 | my $object = shift; | ||||
| 50 | |||||
| 51 | if ($arg->{error}) { | ||||
| 52 | $object = '' unless defined $object; | ||||
| 53 | $message .= ": $!" if $!; | ||||
| 54 | push @{${$arg->{error}}}, {$object => $message}; | ||||
| 55 | } | ||||
| 56 | else { | ||||
| 57 | _carp(defined($object) ? "$message for $object: $!" : "$message: $!"); | ||||
| 58 | } | ||||
| 59 | } | ||||
| 60 | |||||
| 61 | sub make_path { | ||||
| 62 | push @_, {} unless @_ and UNIVERSAL::isa($_[-1],'HASH'); | ||||
| 63 | goto &mkpath; | ||||
| 64 | } | ||||
| 65 | |||||
| 66 | sub mkpath { | ||||
| 67 | my $old_style = !(@_ and UNIVERSAL::isa($_[-1],'HASH')); | ||||
| 68 | |||||
| 69 | my $arg; | ||||
| 70 | my $paths; | ||||
| 71 | |||||
| 72 | if ($old_style) { | ||||
| 73 | my ($verbose, $mode); | ||||
| 74 | ($paths, $verbose, $mode) = @_; | ||||
| 75 | $paths = [$paths] unless UNIVERSAL::isa($paths,'ARRAY'); | ||||
| 76 | $arg->{verbose} = $verbose; | ||||
| 77 | $arg->{mode} = defined $mode ? $mode : 0777; | ||||
| 78 | } | ||||
| 79 | else { | ||||
| 80 | $arg = pop @_; | ||||
| 81 | $arg->{mode} = delete $arg->{mask} if exists $arg->{mask}; | ||||
| 82 | $arg->{mode} = 0777 unless exists $arg->{mode}; | ||||
| 83 | ${$arg->{error}} = [] if exists $arg->{error}; | ||||
| 84 | $arg->{owner} = delete $arg->{user} if exists $arg->{user}; | ||||
| 85 | $arg->{owner} = delete $arg->{uid} if exists $arg->{uid}; | ||||
| 86 | if (exists $arg->{owner} and $arg->{owner} =~ /\D/) { | ||||
| 87 | my $uid = (getpwnam $arg->{owner})[2]; | ||||
| 88 | if (defined $uid) { | ||||
| 89 | $arg->{owner} = $uid; | ||||
| 90 | } | ||||
| 91 | else { | ||||
| 92 | _error($arg, "unable to map $arg->{owner} to a uid, ownership not changed"); | ||||
| 93 | delete $arg->{owner}; | ||||
| 94 | } | ||||
| 95 | } | ||||
| 96 | if (exists $arg->{group} and $arg->{group} =~ /\D/) { | ||||
| 97 | my $gid = (getgrnam $arg->{group})[2]; | ||||
| 98 | if (defined $gid) { | ||||
| 99 | $arg->{group} = $gid; | ||||
| 100 | } | ||||
| 101 | else { | ||||
| 102 | _error($arg, "unable to map $arg->{group} to a gid, group ownership not changed"); | ||||
| 103 | delete $arg->{group}; | ||||
| 104 | } | ||||
| 105 | } | ||||
| 106 | if (exists $arg->{owner} and not exists $arg->{group}) { | ||||
| 107 | $arg->{group} = -1; # chown will leave group unchanged | ||||
| 108 | } | ||||
| 109 | if (exists $arg->{group} and not exists $arg->{owner}) { | ||||
| 110 | $arg->{owner} = -1; # chown will leave owner unchanged | ||||
| 111 | } | ||||
| 112 | $paths = [@_]; | ||||
| 113 | } | ||||
| 114 | return _mkpath($arg, $paths); | ||||
| 115 | } | ||||
| 116 | |||||
| 117 | sub _mkpath { | ||||
| 118 | my $arg = shift; | ||||
| 119 | my $paths = shift; | ||||
| 120 | |||||
| 121 | my(@created,$path); | ||||
| 122 | foreach $path (@$paths) { | ||||
| 123 | next unless defined($path) and length($path); | ||||
| 124 | $path .= '/' if $^O eq 'os2' and $path =~ /^\w:\z/s; # feature of CRT | ||||
| 125 | # Logic wants Unix paths, so go with the flow. | ||||
| 126 | if ($Is_VMS) { | ||||
| 127 | next if $path eq '/'; | ||||
| 128 | $path = VMS::Filespec::unixify($path); | ||||
| 129 | } | ||||
| 130 | next if -d $path; | ||||
| 131 | my $parent = File::Basename::dirname($path); | ||||
| 132 | unless (-d $parent or $path eq $parent) { | ||||
| 133 | push(@created,_mkpath($arg, [$parent])); | ||||
| 134 | } | ||||
| 135 | print "mkdir $path\n" if $arg->{verbose}; | ||||
| 136 | if (mkdir($path,$arg->{mode})) { | ||||
| 137 | push(@created, $path); | ||||
| 138 | if (exists $arg->{owner}) { | ||||
| 139 | # NB: $arg->{group} guaranteed to be set during initialisation | ||||
| 140 | if (!chown $arg->{owner}, $arg->{group}, $path) { | ||||
| 141 | _error($arg, "Cannot change ownership of $path to $arg->{owner}:$arg->{group}"); | ||||
| 142 | } | ||||
| 143 | } | ||||
| 144 | } | ||||
| 145 | else { | ||||
| 146 | my $save_bang = $!; | ||||
| 147 | my ($e, $e1) = ($save_bang, $^E); | ||||
| 148 | $e .= "; $e1" if $e ne $e1; | ||||
| 149 | # allow for another process to have created it meanwhile | ||||
| 150 | if (!-d $path) { | ||||
| 151 | $! = $save_bang; | ||||
| 152 | if ($arg->{error}) { | ||||
| 153 | push @{${$arg->{error}}}, {$path => $e}; | ||||
| 154 | } | ||||
| 155 | else { | ||||
| 156 | _croak("mkdir $path: $e"); | ||||
| 157 | } | ||||
| 158 | } | ||||
| 159 | } | ||||
| 160 | } | ||||
| 161 | return @created; | ||||
| 162 | } | ||||
| 163 | |||||
| 164 | sub remove_tree { | ||||
| 165 | push @_, {} unless @_ and UNIVERSAL::isa($_[-1],'HASH'); | ||||
| 166 | goto &rmtree; | ||||
| 167 | } | ||||
| 168 | |||||
| 169 | sub _is_subdir { | ||||
| 170 | my($dir, $test) = @_; | ||||
| 171 | |||||
| 172 | my($dv, $dd) = File::Spec->splitpath($dir, 1); | ||||
| 173 | my($tv, $td) = File::Spec->splitpath($test, 1); | ||||
| 174 | |||||
| 175 | # not on same volume | ||||
| 176 | return 0 if $dv ne $tv; | ||||
| 177 | |||||
| 178 | my @d = File::Spec->splitdir($dd); | ||||
| 179 | my @t = File::Spec->splitdir($td); | ||||
| 180 | |||||
| 181 | # @t can't be a subdir if it's shorter than @d | ||||
| 182 | return 0 if @t < @d; | ||||
| 183 | |||||
| 184 | return join('/', @d) eq join('/', splice @t, 0, +@d); | ||||
| 185 | } | ||||
| 186 | |||||
| 187 | sub rmtree { | ||||
| 188 | my $old_style = !(@_ and UNIVERSAL::isa($_[-1],'HASH')); | ||||
| 189 | |||||
| 190 | my $arg; | ||||
| 191 | my $paths; | ||||
| 192 | |||||
| 193 | if ($old_style) { | ||||
| 194 | my ($verbose, $safe); | ||||
| 195 | ($paths, $verbose, $safe) = @_; | ||||
| 196 | $arg->{verbose} = $verbose; | ||||
| 197 | $arg->{safe} = defined $safe ? $safe : 0; | ||||
| 198 | |||||
| 199 | if (defined($paths) and length($paths)) { | ||||
| 200 | $paths = [$paths] unless UNIVERSAL::isa($paths,'ARRAY'); | ||||
| 201 | } | ||||
| 202 | else { | ||||
| 203 | _carp ("No root path(s) specified\n"); | ||||
| 204 | return 0; | ||||
| 205 | } | ||||
| 206 | } | ||||
| 207 | else { | ||||
| 208 | $arg = pop @_; | ||||
| 209 | ${$arg->{error}} = [] if exists $arg->{error}; | ||||
| 210 | ${$arg->{result}} = [] if exists $arg->{result}; | ||||
| 211 | $paths = [@_]; | ||||
| 212 | } | ||||
| 213 | |||||
| 214 | $arg->{prefix} = ''; | ||||
| 215 | $arg->{depth} = 0; | ||||
| 216 | |||||
| 217 | my @clean_path; | ||||
| 218 | $arg->{cwd} = getcwd() or do { | ||||
| 219 | _error($arg, "cannot fetch initial working directory"); | ||||
| 220 | return 0; | ||||
| 221 | }; | ||||
| 222 | for ($arg->{cwd}) { /\A(.*)\Z/; $_ = $1 } # untaint | ||||
| 223 | |||||
| 224 | for my $p (@$paths) { | ||||
| 225 | # need to fixup case and map \ to / on Windows | ||||
| 226 | my $ortho_root = $^O eq 'MSWin32' ? _slash_lc($p) : $p; | ||||
| 227 | my $ortho_cwd = $^O eq 'MSWin32' ? _slash_lc($arg->{cwd}) : $arg->{cwd}; | ||||
| 228 | my $ortho_root_length = length($ortho_root); | ||||
| 229 | $ortho_root_length-- if $^O eq 'VMS'; # don't compare '.' with ']' | ||||
| 230 | if ($ortho_root_length && _is_subdir($ortho_root, $ortho_cwd)) { | ||||
| 231 | local $! = 0; | ||||
| 232 | _error($arg, "cannot remove path when cwd is $arg->{cwd}", $p); | ||||
| 233 | next; | ||||
| 234 | } | ||||
| 235 | |||||
| 236 | if ($Is_MacOS) { | ||||
| 237 | $p = ":$p" unless $p =~ /:/; | ||||
| 238 | $p .= ":" unless $p =~ /:\z/; | ||||
| 239 | } | ||||
| 240 | elsif ($^O eq 'MSWin32') { | ||||
| 241 | $p =~ s{[/\\]\z}{}; | ||||
| 242 | } | ||||
| 243 | else { | ||||
| 244 | $p =~ s{/\z}{}; | ||||
| 245 | } | ||||
| 246 | push @clean_path, $p; | ||||
| 247 | } | ||||
| 248 | |||||
| 249 | @{$arg}{qw(device inode perm)} = (lstat $arg->{cwd})[0,1] or do { | ||||
| 250 | _error($arg, "cannot stat initial working directory", $arg->{cwd}); | ||||
| 251 | return 0; | ||||
| 252 | }; | ||||
| 253 | |||||
| 254 | return _rmtree($arg, \@clean_path); | ||||
| 255 | } | ||||
| 256 | |||||
| 257 | sub _rmtree { | ||||
| 258 | my $arg = shift; | ||||
| 259 | my $paths = shift; | ||||
| 260 | |||||
| 261 | my $count = 0; | ||||
| 262 | my $curdir = File::Spec->curdir(); | ||||
| 263 | my $updir = File::Spec->updir(); | ||||
| 264 | |||||
| 265 | my (@files, $root); | ||||
| 266 | ROOT_DIR: | ||||
| 267 | foreach $root (@$paths) { | ||||
| 268 | # since we chdir into each directory, it may not be obvious | ||||
| 269 | # to figure out where we are if we generate a message about | ||||
| 270 | # a file name. We therefore construct a semi-canonical | ||||
| 271 | # filename, anchored from the directory being unlinked (as | ||||
| 272 | # opposed to being truly canonical, anchored from the root (/). | ||||
| 273 | |||||
| 274 | my $canon = $arg->{prefix} | ||||
| 275 | ? File::Spec->catfile($arg->{prefix}, $root) | ||||
| 276 | : $root | ||||
| 277 | ; | ||||
| 278 | |||||
| 279 | my ($ldev, $lino, $perm) = (lstat $root)[0,1,2] or next ROOT_DIR; | ||||
| 280 | |||||
| 281 | if ( -d _ ) { | ||||
| 282 | $root = VMS::Filespec::vmspath(VMS::Filespec::pathify($root)) if $Is_VMS; | ||||
| 283 | |||||
| 284 | if (!chdir($root)) { | ||||
| 285 | # see if we can escalate privileges to get in | ||||
| 286 | # (e.g. funny protection mask such as -w- instead of rwx) | ||||
| 287 | $perm &= 07777; | ||||
| 288 | my $nperm = $perm | 0700; | ||||
| 289 | if (!($arg->{safe} or $nperm == $perm or chmod($nperm, $root))) { | ||||
| 290 | _error($arg, "cannot make child directory read-write-exec", $canon); | ||||
| 291 | next ROOT_DIR; | ||||
| 292 | } | ||||
| 293 | elsif (!chdir($root)) { | ||||
| 294 | _error($arg, "cannot chdir to child", $canon); | ||||
| 295 | next ROOT_DIR; | ||||
| 296 | } | ||||
| 297 | } | ||||
| 298 | |||||
| 299 | my ($cur_dev, $cur_inode, $perm) = (stat $curdir)[0,1,2] or do { | ||||
| 300 | _error($arg, "cannot stat current working directory", $canon); | ||||
| 301 | next ROOT_DIR; | ||||
| 302 | }; | ||||
| 303 | |||||
| 304 | if ($Need_Stat_Check) { | ||||
| 305 | ($ldev eq $cur_dev and $lino eq $cur_inode) | ||||
| 306 | or _croak("directory $canon changed before chdir, expected dev=$ldev ino=$lino, actual dev=$cur_dev ino=$cur_inode, aborting."); | ||||
| 307 | } | ||||
| 308 | |||||
| 309 | $perm &= 07777; # don't forget setuid, setgid, sticky bits | ||||
| 310 | my $nperm = $perm | 0700; | ||||
| 311 | |||||
| 312 | # notabene: 0700 is for making readable in the first place, | ||||
| 313 | # it's also intended to change it to writable in case we have | ||||
| 314 | # to recurse in which case we are better than rm -rf for | ||||
| 315 | # subtrees with strange permissions | ||||
| 316 | |||||
| 317 | if (!($arg->{safe} or $nperm == $perm or chmod($nperm, $curdir))) { | ||||
| 318 | _error($arg, "cannot make directory read+writeable", $canon); | ||||
| 319 | $nperm = $perm; | ||||
| 320 | } | ||||
| 321 | |||||
| 322 | my $d; | ||||
| 323 | $d = gensym() if $] < 5.006; | ||||
| 324 | if (!opendir $d, $curdir) { | ||||
| 325 | _error($arg, "cannot opendir", $canon); | ||||
| 326 | @files = (); | ||||
| 327 | } | ||||
| 328 | else { | ||||
| 329 | 2 | 3.92ms | 2 | 346µs | # spent 205µs (63+142) within File::Path::BEGIN@329 which was called:
# once (63µs+142µs) by File::Temp::BEGIN@145 at line 329 # spent 205µs making 1 call to File::Path::BEGIN@329
# spent 142µs making 1 call to strict::unimport |
| 330 | if (!defined ${"\cTAINT"} or ${"\cTAINT"}) { | ||||
| 331 | # Blindly untaint dir names if taint mode is | ||||
| 332 | # active, or any perl < 5.006 | ||||
| 333 | @files = map { /\A(.*)\z/s; $1 } readdir $d; | ||||
| 334 | } | ||||
| 335 | else { | ||||
| 336 | @files = readdir $d; | ||||
| 337 | } | ||||
| 338 | closedir $d; | ||||
| 339 | } | ||||
| 340 | |||||
| 341 | if ($Is_VMS) { | ||||
| 342 | # Deleting large numbers of files from VMS Files-11 | ||||
| 343 | # filesystems is faster if done in reverse ASCIIbetical order. | ||||
| 344 | # include '.' to '.;' from blead patch #31775 | ||||
| 345 | @files = map {$_ eq '.' ? '.;' : $_} reverse @files; | ||||
| 346 | } | ||||
| 347 | |||||
| 348 | @files = grep {$_ ne $updir and $_ ne $curdir} @files; | ||||
| 349 | |||||
| 350 | if (@files) { | ||||
| 351 | # remove the contained files before the directory itself | ||||
| 352 | my $narg = {%$arg}; | ||||
| 353 | @{$narg}{qw(device inode cwd prefix depth)} | ||||
| 354 | = ($cur_dev, $cur_inode, $updir, $canon, $arg->{depth}+1); | ||||
| 355 | $count += _rmtree($narg, \@files); | ||||
| 356 | } | ||||
| 357 | |||||
| 358 | # restore directory permissions of required now (in case the rmdir | ||||
| 359 | # below fails), while we are still in the directory and may do so | ||||
| 360 | # without a race via '.' | ||||
| 361 | if ($nperm != $perm and not chmod($perm, $curdir)) { | ||||
| 362 | _error($arg, "cannot reset chmod", $canon); | ||||
| 363 | } | ||||
| 364 | |||||
| 365 | # don't leave the client code in an unexpected directory | ||||
| 366 | chdir($arg->{cwd}) | ||||
| 367 | or _croak("cannot chdir to $arg->{cwd} from $canon: $!, aborting."); | ||||
| 368 | |||||
| 369 | # ensure that a chdir upwards didn't take us somewhere other | ||||
| 370 | # than we expected (see CVE-2002-0435) | ||||
| 371 | ($cur_dev, $cur_inode) = (stat $curdir)[0,1] | ||||
| 372 | or _croak("cannot stat prior working directory $arg->{cwd}: $!, aborting."); | ||||
| 373 | |||||
| 374 | if ($Need_Stat_Check) { | ||||
| 375 | ($arg->{device} eq $cur_dev and $arg->{inode} eq $cur_inode) | ||||
| 376 | or _croak("previous directory $arg->{cwd} changed before entering $canon, expected dev=$ldev ino=$lino, actual dev=$cur_dev ino=$cur_inode, aborting."); | ||||
| 377 | } | ||||
| 378 | |||||
| 379 | if ($arg->{depth} or !$arg->{keep_root}) { | ||||
| 380 | if ($arg->{safe} && | ||||
| 381 | ($Is_VMS ? !&VMS::Filespec::candelete($root) : !-w $root)) { | ||||
| 382 | print "skipped $root\n" if $arg->{verbose}; | ||||
| 383 | next ROOT_DIR; | ||||
| 384 | } | ||||
| 385 | if ($Force_Writeable and !chmod $perm | 0700, $root) { | ||||
| 386 | _error($arg, "cannot make directory writeable", $canon); | ||||
| 387 | } | ||||
| 388 | print "rmdir $root\n" if $arg->{verbose}; | ||||
| 389 | if (rmdir $root) { | ||||
| 390 | push @{${$arg->{result}}}, $root if $arg->{result}; | ||||
| 391 | ++$count; | ||||
| 392 | } | ||||
| 393 | else { | ||||
| 394 | _error($arg, "cannot remove directory", $canon); | ||||
| 395 | if ($Force_Writeable && !chmod($perm, ($Is_VMS ? VMS::Filespec::fileify($root) : $root)) | ||||
| 396 | ) { | ||||
| 397 | _error($arg, sprintf("cannot restore permissions to 0%o",$perm), $canon); | ||||
| 398 | } | ||||
| 399 | } | ||||
| 400 | } | ||||
| 401 | } | ||||
| 402 | else { | ||||
| 403 | # not a directory | ||||
| 404 | $root = VMS::Filespec::vmsify("./$root") | ||||
| 405 | if $Is_VMS | ||||
| 406 | && !File::Spec->file_name_is_absolute($root) | ||||
| 407 | && ($root !~ m/(?<!\^)[\]>]+/); # not already in VMS syntax | ||||
| 408 | |||||
| 409 | if ($arg->{safe} && | ||||
| 410 | ($Is_VMS ? !&VMS::Filespec::candelete($root) | ||||
| 411 | : !(-l $root || -w $root))) | ||||
| 412 | { | ||||
| 413 | print "skipped $root\n" if $arg->{verbose}; | ||||
| 414 | next ROOT_DIR; | ||||
| 415 | } | ||||
| 416 | |||||
| 417 | my $nperm = $perm & 07777 | 0600; | ||||
| 418 | if ($Force_Writeable and $nperm != $perm and not chmod $nperm, $root) { | ||||
| 419 | _error($arg, "cannot make file writeable", $canon); | ||||
| 420 | } | ||||
| 421 | print "unlink $canon\n" if $arg->{verbose}; | ||||
| 422 | # delete all versions under VMS | ||||
| 423 | for (;;) { | ||||
| 424 | if (unlink $root) { | ||||
| 425 | push @{${$arg->{result}}}, $root if $arg->{result}; | ||||
| 426 | } | ||||
| 427 | else { | ||||
| 428 | _error($arg, "cannot unlink file", $canon); | ||||
| 429 | $Force_Writeable and chmod($perm, $root) or | ||||
| 430 | _error($arg, sprintf("cannot restore permissions to 0%o",$perm), $canon); | ||||
| 431 | last; | ||||
| 432 | } | ||||
| 433 | ++$count; | ||||
| 434 | last unless $Is_VMS && lstat $root; | ||||
| 435 | } | ||||
| 436 | } | ||||
| 437 | } | ||||
| 438 | return $count; | ||||
| 439 | } | ||||
| 440 | |||||
| 441 | sub _slash_lc { | ||||
| 442 | # fix up slashes and case on MSWin32 so that we can determine that | ||||
| 443 | # c:\path\to\dir is underneath C:/Path/To | ||||
| 444 | my $path = shift; | ||||
| 445 | $path =~ tr{\\}{/}; | ||||
| 446 | return lc($path); | ||||
| 447 | } | ||||
| 448 | |||||
| 449 | 1 | 31µs | 1; | ||
| 450 | __END__ |