# $Id: //depot/prod/test/main/lib/Utils/File/Path.pm#1 $ # # Copyright (c) 2007 Network Appliance, Inc., All Rights Reserved # Permission is granted to use this script on a Network Appliance Product. # Any other use, modification, or distribution is prohibited # without prior written consent from Network Appliance, Inc. # ## @summary Provides some File Path functions that can not be found in the ## public domain ## ## @author medmonds@netapp.com ## @status public ## @pod here ## =pod =head1 Author Michael Edmonds =head1 Owner GX Automation Framework (dl-afd@netapp.com) =head1 NAME Utils::File::Path.pm =head1 DESCRIPTION C Provides some File Path functions that can not be found in the public domain. =head1 See Also File::Path on CPAN =head1 SYNOPSIS use Utils::File::Path; my $Output = Utils::File::Path::cleantree("/some/dir", 1, 1); =head1 Public Methods =cut package Utils::File::Path; use strict; use threads; use threads::shared; use Data::Dumper; use Params::Validate qw(:all); use TracePkg; our $Trace; BEGIN { $Trace = TracePkg->new(); } # end BEGIN =head2 cleantree =over 4 C =Description This is a direct rip off from File::Path::rmtree. I just didn't want to damage the structure of the tree ... just rake the leaves =item Input =item $dir (Required) directory path to clean =item $verbose = <0 | 1> (Optional) Default = 0 =item $safe = <0 | 1> (Optional) Default = 0 when set to 1, skips any files to which you do not have delete access =item Output quantity of files deleted =item Example my $count = Utils::File::Path::cleantree("/some/dir", 1, 0); =back =cut sub cleantree { my($roots, $verbose, $safe) = @_; my $Is_VMS = $^O eq 'VMS'; my $Is_MacOS = $^O eq 'MacOS'; my $force_writeable = ($^O eq 'os2' || $^O eq 'dos' || $^O eq 'MSWin32' || $^O eq 'amigaos' || $^O eq 'MacOS' || $^O eq 'epoc'); my(@files); my($count) = 0; $verbose ||= 0; $safe ||= 0; if ( defined($roots) && length($roots) ) { $roots = [$roots] unless ref $roots; } else { $Trace->warn(msg => "No root path(s) specified\n"); return -1; } my($root); foreach $root (@{$roots}) { if ($Is_MacOS) { $root = ":$root" if $root !~ /:/; $root =~ s#([^:])\z#$1:#; } else { $root =~ s#/\z##; } (undef, undef, my $rp) = lstat $root or next; $rp &= 07777; # don't forget setuid, setgid, sticky bits if ( -d _ ) { # notabene: 0700 is for making readable in the first place, # it's also intended to change it to writable in case we have # to recurse in which case we are better than rm -rf for # subtrees with strange permissions chmod($rp | 0700, ($Is_VMS ? VMS::Filespec::fileify($root) : $root)) or $Trace->warn(msg => "Can't make directory $root read+writeable: $!") unless $safe; if (opendir my $d, $root) { no strict 'refs'; if (!defined ${"\cTAINT"} or ${"\cTAINT"}) { # Blindly untaint dir names @files = map { /^(.*)$/s ; $1 } readdir $d; } else { @files = readdir $d; } closedir $d; } else { $Trace->warn(msg => "Can't read $root: $!"); @files = (); } # Deleting large numbers of files from VMS Files-11 filesystems # is faster if done in reverse ASCIIbetical order @files = reverse @files if $Is_VMS; ($root = VMS::Filespec::unixify($root)) =~ s#\.dir\z## if $Is_VMS; if ($Is_MacOS) { @files = map("$root$_", @files); } else { @files = map("$root/$_", grep $_!~/^\.{1,2}\z/s,@files); } $count += cleantree(\@files,$verbose,$safe); if ($safe && ($Is_VMS ? !&VMS::Filespec::candelete($root) : !-w $root)) { $Trace->comment(msg => "skipped $root\n") if $verbose; next; } chmod $rp | 0700, $root or $Trace->warn(msg => "Can't make directory $root writeable: $!") if $force_writeable; } else { if ($safe && ($Is_VMS ? !&VMS::Filespec::candelete($root) : !(-l $root || -w $root))) { $Trace->comment(msg => "skipped $root\n") if $verbose; next; } chmod $rp | 0600, $root or $Trace->warn(msg => "Can't make file $root writeable: $!") if $force_writeable; $Trace->comment(msg => "unlink $root\n") if $verbose; # delete all versions under VMS for (;;) { unless (unlink $root) { $Trace->warn(msg => "Can't unlink file $root: $!"); if ($force_writeable) { chmod $rp, $root or $Trace->warn(msg => "and can't restore permissions to " . sprintf("0%o",$rp) . "\n"); } last; } ++$count; last unless $Is_VMS && lstat $root; } } } return $count; } 1;