X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=blobdiff_plain;f=lib%2FCwd.pm;h=d7e60d6dc979572e2176b781797921bd0b11d49e;hb=c7574462553caa93de43b87874d7657569d04353;hp=385f9723b78ccdcde9b2418a24c2f570bbc84cab;hpb=0d2079faa739aaa999ddace336394cba070395f2;p=p5sagit%2Fp5-mst-13.2.git diff --git a/lib/Cwd.pm b/lib/Cwd.pm index 385f972..d7e60d6 100644 --- a/lib/Cwd.pm +++ b/lib/Cwd.pm @@ -1,5 +1,5 @@ package Cwd; -require 5.000; +use 5.006; =head1 NAME @@ -8,70 +8,132 @@ 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. + +=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). + +Unfortunately, cwd() tends to break if called under taint mode. + +=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). + +=item realpath + + my $abs_path = realpath($file); + +A synonym for abs_path(). -The fast_abs_path() function looks the same as abs_path() but runs -faster and, like fastcwd(), is more dangerous. +=item fast_abs_path -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. + my $abs_path = abs_path($file); + +A more dangerous, but potentially faster version of abs_path. + +=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. + + +=head1 NOTES + +=over 4 + +=item * + +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, +calls `pwd`. Likewise, the C function is an alias for +C. + +=back + +=head1 SEE ALSO + +L =cut @@ -79,17 +141,53 @@ use strict; use Carp; -our $VERSION = '2.04'; +our $VERSION = '2.06'; use base qw/ Exporter /; our @EXPORT = qw(cwd getcwd fastcwd fastgetcwd); our @EXPORT_OK = qw(chdir abs_path fast_abs_path realpath fast_realpath); +# sys_cwd may keep the builtin command + +# All the functionality of this module may provided by builtins, +# there is no sense to process the rest of the file. +# The best choice may be to have this in BEGIN, but how to return from BEGIN? + +if ($^O eq 'os2' && defined &sys_cwd && defined &sys_abspath) { + local $^W = 0; + *cwd = \&sys_cwd; + *getcwd = \&cwd; + *fastgetcwd = \&cwd; + *fastcwd = \&cwd; + *abs_path = \&sys_abspath; + *fast_abs_path = \&abs_path; + *realpath = \&abs_path; + *fast_realpath = \&abs_path; + return 1; +} -# The 'natural and safe form' for UNIX (pwd may be setuid root) +eval { + require XSLoader; + undef *Cwd::fastcwd; # avoid redefinition warning + XSLoader::load('Cwd'); +}; + + +# Find the pwd command in the expected locations. We assume these +# are safe. This prevents _backtick_pwd() consulting $ENV{PATH} +# so everything works under taint mode. +my $pwd_cmd; +foreach my $try (qw(/bin/pwd /usr/bin/pwd)) { + if( -x $try ) { + $pwd_cmd = $try; + last; + } +} +$pwd_cmd ||= 'pwd'; +# The 'natural and safe form' for UNIX (pwd may be setuid root) sub _backtick_pwd { - my $cwd = `pwd`; + my $cwd = `$pwd_cmd`; # `pwd` may fail e.g. if the disk is full chomp($cwd) if defined $cwd; $cwd; @@ -121,17 +219,51 @@ sub getcwd abs_path('.'); } -# Now a callout to an XSUB. We have to delay booting of the XSUB -# until the first time fastcwd is called since Cwd::cwd is needed in the -# building of perl when dynamic loading may be unavailable -my $booted = 0; + +# 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 { - unless ($booted) { - require XSLoader; - XSLoader::load("Cwd"); - ++$booted; + 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); } - return &Cwd::_fastcwd; + $path = '/' . join('/', @path); + if ($^O eq 'apollo') { $path = "/".$path; } + # At this point $path may be tainted (if tainting) and chdir would fail. + # To be more useful we untaint it then check that we landed where we started. + $path = $1 if $path =~ /^(.*)\z/s; # untaint + CORE::chdir($path) || return undef; + ($cdev, $cino) = stat('.'); + die "Unstable directory path, current directory changed unexpectedly" + if $cdev != $orig_cdev || $cino != $orig_cino; + $path; } @@ -170,7 +302,14 @@ sub chdir { my $newdir = @_ ? shift : ''; # allow for no arg (chdir to HOME dir) $newdir =~ s|///*|/|g unless $^O eq 'MSWin32'; chdir_init() unless $chdir_init; + my $newpwd; + if ($^O eq 'MSWin32') { + # get the full path name *before* the chdir() + $newpwd = Win32::GetFullPathName($newdir); + } + return 0 unless CORE::chdir $newdir; + if ($^O eq 'VMS') { return $ENV{'PWD'} = $ENV{'DEFAULT'} } @@ -178,7 +317,7 @@ sub chdir { return $ENV{'PWD'} = cwd(); } elsif ($^O eq 'MSWin32') { - $ENV{'PWD'} = Win32::GetFullPathName($newdir); + $ENV{'PWD'} = $newpwd; return 1; } @@ -198,11 +337,10 @@ sub chdir { 1; } -# Taken from Cwd.pm It is really getcwd with an optional -# parameter instead of '.' -# -sub abs_path +# 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); @@ -255,13 +393,15 @@ sub abs_path $cwd; } + # added function alias for those of us more # used to the libc function. --tchrist 27-Jan-00 *realpath = \&abs_path; sub fast_abs_path { my $cwd = getcwd(); - my $path = @_ ? shift : '.'; + require File::Spec; + my $path = @_ ? shift : File::Spec->curdir; CORE::chdir($path) || croak "Cannot chdir to $path:$!"; my $realpath = getcwd(); CORE::chdir($cwd) || croak "Cannot chdir back to $cwd:$!"; @@ -359,6 +499,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 @@ -375,7 +516,7 @@ sub _epoc_cwd { *fastcwd = \&_dos_cwd; *abs_path = \&fast_abs_path; } - elsif ($^O eq 'qnx') { + elsif ($^O =~ m/^(?:qnx|nto)$/ ) { *cwd = \&_qnx_cwd; *getcwd = \&_qnx_cwd; *fastgetcwd = \&_qnx_cwd; @@ -404,13 +545,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";