Tryag File Manager
Home
-
Turbo Force
Current Path :
/
proc
/
self
/
root
/
usr
/
lib
/
perl5
/
5.8.8
/
File
/
Upload File :
New :
File
Dir
//proc/self/root/usr/lib/perl5/5.8.8/File/Path.pm
package File::Path; =head1 NAME File::Path - create or remove directory trees =head1 SYNOPSIS use File::Path; mkpath(['/foo/bar/baz', 'blurfl/quux'], 1, 0711); rmtree(['foo/bar/baz', 'blurfl/quux'], 1, 1); =head1 DESCRIPTION The C<mkpath> function provides a convenient way to create directories, even if your C<mkdir> kernel call won't create more than one level of directory at a time. C<mkpath> takes three arguments: =over 4 =item * the name of the path to create, or a reference to a list of paths to create, =item * a boolean value, which if TRUE will cause C<mkpath> to print the name of each directory as it is created (defaults to FALSE), and =item * the numeric mode to use when creating the directories (defaults to 0777), to be modified by the current umask. =back It returns a list of all directories (including intermediates, determined using the Unix '/' separator) created. If a system error prevents a directory from being created, then the C<mkpath> function throws a fatal error with C<Carp::croak>. This error can be trapped with an C<eval> block: eval { mkpath($dir) }; if ($@) { print "Couldn't create $dir: $@"; } Similarly, the C<rmtree> function provides a convenient way to delete a subtree from the directory structure, much like the Unix command C<rm -r>. C<rmtree> takes three arguments: =over 4 =item * the root of the subtree to delete, or a reference to a list of roots. All of the files and directories below each root, as well as the roots themselves, will be deleted. =item * a boolean value, which if TRUE will cause C<rmtree> to print a message each time it examines a file, giving the name of the file, and indicating whether it's using C<rmdir> or C<unlink> to remove it, or that it's skipping it. (defaults to FALSE) =item * a boolean value, which if FALSE (the default for non-root users) will cause C<rmtree> to adjust the mode of directories (if required) prior to attempting to remove the contents. Note that on interruption or failure of C<rmtree>, directories may be left with more permissive modes for the owner. =back It returns the number of files successfully deleted. Symlinks are simply deleted and not followed. =head1 DIAGNOSTICS =over 4 =item * On Windows, if C<mkpath> gives you the warning: B<No such file or directory>, this may mean that you've exceeded your filesystem's maximum path length. =back =head1 AUTHORS Tim Bunce <F<Tim.Bunce@ig.co.uk>> and Charles Bailey <F<bailey@newman.upenn.edu>> =cut use 5.006; use Carp; use File::Basename (); use Exporter (); use strict; use warnings; our $VERSION = "1.08"; our @ISA = qw( Exporter ); our @EXPORT = qw( mkpath rmtree ); my $Is_VMS = $^O eq 'VMS'; my $Is_MacOS = $^O eq 'MacOS'; # These OSes complain if you want to remove a file that you have no # write permission to: my $force_writeable = ($^O eq 'os2' || $^O eq 'dos' || $^O eq 'MSWin32' || $^O eq 'amigaos' || $^O eq 'MacOS' || $^O eq 'epoc'); sub mkpath { my($paths, $verbose, $mode) = @_; # $paths -- either a path string or ref to list of paths # $verbose -- optional print "mkdir $path" for each directory created # $mode -- optional permissions, defaults to 0777 local($")=$Is_MacOS ? ":" : "/"; $mode = 0777 unless defined($mode); $paths = [$paths] unless ref $paths; my(@created,$path); foreach $path (@$paths) { $path .= '/' if $^O eq 'os2' and $path =~ /^\w:\z/s; # feature of CRT # Logic wants Unix paths, so go with the flow. if ($Is_VMS) { next if $path eq '/'; $path = VMS::Filespec::unixify($path); if ($path =~ m:^(/[^/]+)/?\z:) { $path = $1.'/000000'; } } next if -d $path; my $parent = File::Basename::dirname($path); unless (-d $parent or $path eq $parent) { push(@created,mkpath($parent, $verbose, $mode)); } print "mkdir $path\n" if $verbose; unless (mkdir($path,$mode)) { my $e = $!; # allow for another process to have created it meanwhile $! = $e, croak ("mkdir $path: $e") unless -d $path; } push(@created, $path); } @created; } sub _rmtree; sub _rmtree { my ($path, $prefix, $up, $up_dev, $up_ino, $verbose, $safe) = @_; my $up_name = $up eq '..' ? 'parent' : 'initial'; my ($dev, $ino, $perm) = lstat $path or return 0; unless (-d _) { print "unlink $prefix$path\n" if $verbose; unless (unlink $path) { carp "Can't remove file $prefix$path ($!)"; return 0; } return 1; } $perm &= 07777; my $fixperm = 0; unless (chdir $path) { my $nperm = $perm | 0100; if (!($safe or $nperm == $perm or (chmod(0700, $path) and $fixperm = 1))) { carp "Can't make directory $prefix$path executable ($!)"; return 0; } elsif (!chdir($path)) { carp "Can't chdir to $prefix$path ($!)"; return 0; } $perm = $nperm; } # avoid a race condition where a directory may be replaced by a # symlink between the lstat and the chdir my ($new_dev, $new_ino) = stat '.'; unless ("$new_dev:$new_ino" eq "$dev:$ino") { croak "Directory $prefix$path changed before chdir, aborting"; } my $nperm = $perm | 0700; unless ($safe or ($nperm == $perm and not $fixperm) or chmod $nperm, '.') { carp "Can't make directory $prefix$path read+writeable ($!)"; $nperm = $perm; } my $count = 0; if (opendir my $dir, '.') { my $entry; while (defined ($entry = readdir $dir)) { next if $entry =~ /^\.\.?$/; $entry =~ /^(.*)$/s; $entry = $1; # untaint $count += _rmtree $entry, "$prefix$path/", '..', $dev, $ino, $verbose, $safe; } closedir $dir; } # restore directory permissions if required (in case the rmdir # below fails) now, while we're still in the directory and may do # so without a race via '.' unless ($safe or $nperm == $perm or chmod $perm, '.') { carp "Can't restore permissions on directory $prefix$path ($!)"; } # don't leave the caller in an unexpected directory unless (chdir $up) { croak "Can't return to $up_name directory from $prefix$path ($!)"; } # ensure that a chdir .. didn't take us somewhere other than # where we expected (see CVE-2002-0435) unless (($new_dev, $new_ino) = stat '.' and "$new_dev:$new_ino" eq "$up_dev:$up_ino") { croak "\u$up_name directory changed since entering $prefix$path"; } print "rmdir $prefix$path\n" if $verbose; if (rmdir $path) { $count++; } else { carp "Can't remove directory $prefix$path ($!)"; } return $count; } sub rmtree { my ($p, $verbose, $safe) = @_; $p = [] unless defined $p and length $p; $p = [ $p ] unless ref $p; my @paths = grep defined && length, @$p; # default to "unsafe" for non-root (will chmod dirs) $safe = $> ? 0 : 1 unless defined $safe; unless (@paths) { carp "No root path(s) specified"; return; } opendir my $oldpwd, '.' or do { carp "Can't fetch initial working directory"; return; }; my ($dev, $ino) = stat '.' or do { carp "Can't stat initial working directory"; return; }; my $count = 0; for my $path (@paths) { $count += _rmtree $path, '', $oldpwd, $dev, $ino, $verbose, $safe; } $count; } 1;