From a0c9c202edde87fa4f6c175b545b8b4d311d45b9 Mon Sep 17 00:00:00 2001 From: Jarkko Hietaniemi Date: Thu, 6 Sep 2001 11:52:56 +0000 Subject: [PATCH] Re-introduce pure-Perl fall-back for abs_path, re-introduce #11898. p4raw-id: //depot/perl@11910 --- lib/Cwd.pm | 113 +++++++++++++++++++++++++++++++++++++++++++++++++++---- lib/File/Find.pm | 2 +- 2 files changed, 106 insertions(+), 9 deletions(-) diff --git a/lib/Cwd.pm b/lib/Cwd.pm index 79725d1..88afca2 100644 --- a/lib/Cwd.pm +++ b/lib/Cwd.pm @@ -218,6 +218,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. + # 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; +} + + # Keeps track of current working directory in PWD environment var # Usage: # use Cwd 'chdir'; @@ -288,6 +336,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; @@ -438,13 +543,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"; diff --git a/lib/File/Find.pm b/lib/File/Find.pm index eb4b2de..bfcbcfd 100644 --- a/lib/File/Find.pm +++ b/lib/File/Find.pm @@ -475,7 +475,7 @@ sub _find_opt { $pre_process, $post_process, $dangling_symlinks); local($dir, $name, $fullname, $prune); - my $cwd = $wanted->{bydepth} ? Cwd::fastcwd() : Cwd::cwd(); + my $cwd = $wanted->{bydepth} ? Cwd::fastcwd() : Cwd::getcwd(); my $cwd_untainted = $cwd; my $check_t_cwd = 1; $wanted_callback = $wanted->{wanted}; -- 2.7.4