X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=blobdiff_plain;f=lib%2FCwd.pm;h=7f8ef6543b9ed0eda68135ef78ab4c5fa6a58be3;hb=3b0db4f96671dacfd3421850abb588b84e2ce6da;hp=37217fa01eda58bfc468f7f1a935d618e29c2600;hpb=3547aa9a8aaf2eba7e5ab912d32d7292dd5fcb51;p=p5sagit%2Fp5-mst-13.2.git diff --git a/lib/Cwd.pm b/lib/Cwd.pm index 37217fa..7f8ef65 100644 --- a/lib/Cwd.pm +++ b/lib/Cwd.pm @@ -1,5 +1,5 @@ package Cwd; -require 5.6.0; +use 5.006; =head1 NAME @@ -8,70 +8,118 @@ Cwd - get pathname of current working directory =head1 SYNOPSIS use Cwd; - $dir = cwd; + my $dir = getcwd; - use Cwd; - $dir = getcwd; + use Cwd 'abs_path'; + my $abs_path = abs_path($file); - use Cwd; - $dir = fastcwd; +=head1 DESCRIPTION - use Cwd; - $dir = fastgetcwd; +This module provides functions for determining the pathname of the +current working directory. It is recommended that getcwd (or another +*cwd() function) be used in I code to ensure portability. - use Cwd 'chdir'; - chdir "/tmp"; - print $ENV{'PWD'}; +By default, it exports the functions cwd(), getcwd(), fastcwd(), and +fastgetcwd() into the caller's namespace. - use Cwd 'abs_path'; # aka realpath() - print abs_path($ENV{'PWD'}); - use Cwd 'fast_abs_path'; - print fast_abs_path($ENV{'PWD'}); +=head2 getcwd and friends -=head1 DESCRIPTION +Each of these functions are called without arguments and return the +absolute path of the current working directory. -This module provides functions for determining the pathname of the -current working directory. By default, it exports the functions -cwd(), getcwd(), fastcwd(), and fastgetcwd() into the caller's -namespace. Each of these functions are called without arguments and -return the absolute path of the current working directory. It is -recommended that cwd (or another *cwd() function) be used in I -code to ensure portability. - -The cwd() is the most natural and safe form for the current -architecture. For most systems it is identical to `pwd` (but without -the trailing line terminator). - -The getcwd() function re-implements the getcwd(3) (or getwd(3)) functions -in Perl. - -The fastcwd() function looks the same as getcwd(), but runs faster. -It's also more dangerous because it might conceivably chdir() you out -of a directory that it can't chdir() you back into. If fastcwd -encounters a problem it will return undef but will probably leave you -in a different directory. For a measure of extra security, if -everything appears to have worked, the fastcwd() function will check -that it leaves you in the same directory that it started in. If it has -changed it will C with the message "Unstable directory path, -current directory changed unexpectedly". That should never happen. +=over 4 + +=item getcwd + + my $cwd = getcwd(); + +Returns the current working directory. + +Re-implements the getcwd(3) (or getwd(3)) functions in Perl. + +Taint-safe. + +=item cwd + + my $cwd = cwd(); + +The cwd() is the most natural form for the current architecture. For +most systems it is identical to `pwd` (but without the trailing line +terminator). + +Taint-safe. + +=item fastcwd + + my $cwd = fastcwd(); + +A more dangerous version of getcwd(), but potentially faster. + +It might conceivably chdir() you out of a directory that it can't +chdir() you back into. If fastcwd encounters a problem it will return +undef but will probably leave you in a different directory. For a +measure of extra security, if everything appears to have worked, the +fastcwd() function will check that it leaves you in the same directory +that it started in. If it has changed it will C with the message +"Unstable directory path, current directory changed +unexpectedly". That should never happen. + +=item fastgetcwd + + my $cwd = fastgetcwd(); The fastgetcwd() function is provided as a synonym for cwd(). -The abs_path() function takes a single argument and returns the -absolute pathname for that argument. It uses the same algorithm as -getcwd(). (Actually, getcwd() is abs_path(".")) Symbolic links and -relative-path components ("." and "..") are resolved to return the -canonical pathname, just like realpath(3). This function is also -callable as realpath(). +=back + + +=head2 abs_path and friends + +These functions are exported only on request. They each take a single +argument and return the absolute pathname for it. + +=over 4 + +=item abs_path + + my $abs_path = abs_path($file); + +Uses the same algorithm as getcwd(). Symbolic links and relative-path +components ("." and "..") are resolved to return the canonical +pathname, just like realpath(3). + +Taint-safe. + +=item realpath + + my $abs_path = realpath($file); + +A synonym for abs_path(). + +Taint-safe. -The fast_abs_path() function looks the same as abs_path() but runs -faster and, like fastcwd(), is more dangerous. +=item fast_abs_path + + my $abs_path = fast_abs_path($file); + +A more dangerous, but potentially faster version of abs_path. + +This function is B taint-safe : you can't use it in programs +that work under taint mode. + +=back + +=head2 $ENV{PWD} + +If you ask to override your chdir() built-in function, + + use Cwd qw(chdir); + +then your PWD environment variable will be kept up to date. Note that +it will only be kept up to date if all packages which use chdir import +it from Cwd. -If you ask to override your chdir() built-in function, then your PWD -environment variable will be kept up to date. (See -L.) Note that it will only be -kept up to date if all packages which use chdir import it from Cwd. =head1 NOTES @@ -79,14 +127,11 @@ kept up to date if all packages which use chdir import it from Cwd. =item * -On Mac OS (Classic), the path separator is ':', not '/', and the -current directory is denoted as ':', not '.'. To move up the directory -tree, you will use '::' to move up one level, but ':::' and so on to -move up the tree two or more levels (i.e. the equivalent to '../../..' -is '::::'). Generally, you should be careful about specifying relative pathnames. -While a full path always begins with a volume name, a relative pathname -should always begin with a ':'. If specifying a volume name only, a -trailing ':' is required. +Since the path seperators are different on some operating systems ('/' +on Unix, ':' on MacPerl, etc...) we recommend you use the File::Spec +modules wherever portability is a concern. + +=item * Actually, on Mac OS, the C, C and C functions are all aliases for the C function, which, on Mac OS, @@ -95,13 +140,17 @@ C. =back +=head1 SEE ALSO + +L + =cut use strict; use Carp; -our $VERSION = '2.05'; +our $VERSION = '2.06'; use base qw/ Exporter /; our @EXPORT = qw(cwd getcwd fastcwd fastgetcwd); @@ -128,6 +177,7 @@ if ($^O eq 'os2' && defined &sys_cwd && defined &sys_abspath) { eval { require XSLoader; + undef *Cwd::fastcwd; # avoid redefinition warning XSLoader::load('Cwd'); }; @@ -142,11 +192,23 @@ foreach my $try (qw(/bin/pwd /usr/bin/pwd)) { last; } } -$pwd_cmd ||= 'pwd'; +unless ($pwd_cmd) { + if (-x '/QOpenSys/bin/pwd') { # OS/400 PASE. + $pwd_cmd = '/QOpenSys/bin/pwd' ; + } else { + # Isn't this wrong? _backtick_pwd() will fail if somenone has + # pwd in their path but it is not /bin/pwd or /usr/bin/pwd? + # See [perl #16774]. --jhi + $pwd_cmd = 'pwd'; + } +} # The 'natural and safe form' for UNIX (pwd may be setuid root) sub _backtick_pwd { + local @ENV{qw(PATH IFS CDPATH ENV BASH_ENV)}; my $cwd = `$pwd_cmd`; + # Belt-and-suspenders in case someone said "undef $/". + local $/ = "\n"; # `pwd` may fail e.g. if the disk is full chomp($cwd) if defined $cwd; $cwd; @@ -157,7 +219,9 @@ sub _backtick_pwd { unless(defined &cwd) { # The pwd command is not available in some chroot(2)'ed environments - if($^O eq 'MacOS' || grep { -x "$_/pwd" } split(':', $ENV{PATH})) { + if( $^O eq 'MacOS' || (defined $ENV{PATH} && + grep { -x "$_/pwd" } split(':', $ENV{PATH})) ) + { *cwd = \&_backtick_pwd; } else { @@ -178,6 +242,54 @@ sub getcwd abs_path('.'); } + +# By John Bazik +# +# Usage: $cwd = &fastcwd; +# +# This is a faster version of getcwd. It's also more dangerous because +# you might chdir out of a directory that you can't chdir back into. + +sub fastcwd { + my($odev, $oino, $cdev, $cino, $tdev, $tino); + my(@path, $path); + local(*DIR); + + my($orig_cdev, $orig_cino) = stat('.'); + ($cdev, $cino) = ($orig_cdev, $orig_cino); + for (;;) { + my $direntry; + ($odev, $oino) = ($cdev, $cino); + CORE::chdir('..') || return undef; + ($cdev, $cino) = stat('.'); + last if $odev == $cdev && $oino == $cino; + opendir(DIR, '.') || return undef; + for (;;) { + $direntry = readdir(DIR); + last unless defined $direntry; + next if $direntry eq '.'; + next if $direntry eq '..'; + + ($tdev, $tino) = lstat($direntry); + last unless $tdev != $odev || $tino != $oino; + } + closedir(DIR); + return undef unless defined $direntry; # should never happen + unshift(@path, $direntry); + } + $path = '/' . join('/', @path); + if ($^O eq 'apollo') { $path = "/".$path; } + # At this point $path may be tainted (if tainting) and chdir would fail. + # Untaint it then check that we landed where we started. + $path =~ /^(.*)\z/s # untaint + && CORE::chdir($1) or return undef; + ($cdev, $cino) = stat('.'); + die "Unstable directory path, current directory changed unexpectedly" + if $cdev != $orig_cdev || $cino != $orig_cino; + $path; +} + + # Keeps track of current working directory in PWD environment var # Usage: # use Cwd 'chdir'; @@ -248,6 +360,63 @@ sub chdir { 1; } + +# In case the XS version doesn't load. +*abs_path = \&_perl_abs_path unless defined &abs_path; +sub _perl_abs_path +{ + my $start = @_ ? shift : '.'; + my($dotdots, $cwd, @pst, @cst, $dir, @tst); + + unless (@cst = stat( $start )) + { + carp "stat($start): $!"; + return ''; + } + $cwd = ''; + $dotdots = $start; + do + { + $dotdots .= '/..'; + @pst = @cst; + unless (opendir(PARENT, $dotdots)) + { + carp "opendir($dotdots): $!"; + return ''; + } + unless (@cst = stat($dotdots)) + { + carp "stat($dotdots): $!"; + closedir(PARENT); + return ''; + } + if ($pst[0] == $cst[0] && $pst[1] == $cst[1]) + { + $dir = undef; + } + else + { + do + { + unless (defined ($dir = readdir(PARENT))) + { + carp "readdir($dotdots): $!"; + closedir(PARENT); + return ''; + } + $tst[0] = $pst[0]+1 unless (@tst = lstat("$dotdots/$dir")) + } + while ($dir eq '.' || $dir eq '..' || $tst[0] != $pst[0] || + $tst[1] != $pst[1]); + } + $cwd = (defined $dir ? "$dir" : "" ) . "/$cwd" ; + closedir(PARENT); + } while (defined $dir); + chop($cwd) unless $cwd eq '/'; # drop the trailing / + $cwd; +} + + # added function alias for those of us more # used to the libc function. --tchrist 27-Jan-00 *realpath = \&abs_path; @@ -256,9 +425,10 @@ sub fast_abs_path { my $cwd = getcwd(); require File::Spec; my $path = @_ ? shift : File::Spec->curdir; - CORE::chdir($path) || croak "Cannot chdir to $path:$!"; + CORE::chdir($path) || croak "Cannot chdir to $path: $!"; my $realpath = getcwd(); - CORE::chdir($cwd) || croak "Cannot chdir back to $cwd:$!"; + -d $cwd && CORE::chdir($cwd) || + croak "Cannot chdir back to $cwd: $!"; $realpath; } @@ -318,12 +488,18 @@ sub _dos_cwd { } sub _qnx_cwd { + local $ENV{PATH} = ''; + local $ENV{CDPATH} = ''; + local $ENV{ENV} = ''; $ENV{'PWD'} = `/usr/bin/fullpath -t`; chop $ENV{'PWD'}; return $ENV{'PWD'}; } sub _qnx_abs_path { + local $ENV{PATH} = ''; + local $ENV{CDPATH} = ''; + local $ENV{ENV} = ''; my $path = @_ ? shift : '.'; my $realpath=`/usr/bin/fullpath -t $path`; chop $realpath; @@ -353,6 +529,7 @@ sub _epoc_cwd { *fastcwd = \&_NT_cwd; *fastgetcwd = \&_NT_cwd; *abs_path = \&fast_abs_path; + *realpath = \&fast_abs_path; } elsif ($^O eq 'os2') { # sys_cwd may keep the builtin command @@ -398,13 +575,5 @@ sub _epoc_cwd { } } -# package main; eval join('',) || die $@; # quick test 1; - -__END__ -BEGIN { import Cwd qw(:DEFAULT chdir); } -print join("\n", cwd, getcwd, fastcwd, ""); -chdir('..'); -print join("\n", cwd, getcwd, fastcwd, ""); -print "$ENV{PWD}\n";