From: Conrad E. Kimball Date: Thu, 7 Aug 1997 00:00:00 +0000 (+0000) Subject: (3) File::Find::find()/finddepth() bugs with toplevel paths X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=commitdiff_plain;h=d0e28714d06a28aece55f6d80cabd610184a6bd0;p=p5sagit%2Fp5-mst-13.2.git (3) File::Find::find()/finddepth() bugs with toplevel paths The File::Find module exhibits the following defects: 1) If the top-level directory is a symbolic link to another directory, the find() and finddepth() functions follow that symbolic link and traverse that directory. This behavior is both contrary to the way the real find command works and contrary to the way find() and finddepth() treat symbolic links that occur lower down in the directory hierarchy (which aren't followed). Example: $ cd $HOME $ mkdir findbug; cd findbug $ ln -s /usr usr $ find usr -print usr $ find2perl usr -print | perl usr usr/lost+found usr/tmp usr/tmp/.zma25637cbbb ... 2) If the wanted() function sets $prune = 1 for a toplevel directory, the find() function ignores it. It honors $prune for all lower level directories, but not the toplevel ones. This, too, is contrary to the way the real find command works. Example: $ find /usr -print -prune /usr $ find2perl /usr -print -prune | perl /usr /usr/lost+found /usr/tmp /usr/bin /usr/man /usr/etc /usr/lib /usr/netdemo /usr/include /usr/adm ... 3) If finddepth() is passed a toplevel path that is not a directory, it fails to set $name before calling the wanted() function. This, too, is contrary to the way the real find command works. Example: $ cd $HOME $ find /dev/null -depth -print /dev/null $ find2perl /dev/null -depth -print | perl $ The following patch corrects all three defects: p5p-msgid: 199707040045.RAA24459@mailgate2.boeing.com --- diff --git a/lib/File/Find.pm b/lib/File/Find.pm index 1faea50..1d565f2 100644 --- a/lib/File/Find.pm +++ b/lib/File/Find.pm @@ -78,18 +78,22 @@ sub find { # compatibility. local($topdir,$topdev,$topino,$topmode,$topnlink); foreach $topdir (@_) { - (($topdev,$topino,$topmode,$topnlink) = stat($topdir)) + (($topdev,$topino,$topmode,$topnlink) = + ($Is_VMS ? stat($topdir) : lstat($topdir))) || (warn("Can't stat $topdir: $!\n"), next); if (-d _) { if (chdir($topdir)) { ($dir,$_) = ($topdir,'.'); $name = $topdir; + $prune = 0; &$wanted; - my $fixtopdir = $topdir; - $fixtopdir =~ s,/$,, ; - $fixtopdir =~ s/\.dir$// if $Is_VMS; - $fixtopdir =~ s/\\dir$// if $Is_NT; - &finddir($wanted,$fixtopdir,$topnlink); + if (!$prune) { + my $fixtopdir = $topdir; + $fixtopdir =~ s,/$,, ; + $fixtopdir =~ s/\.dir$// if $Is_VMS; + $fixtopdir =~ s/\\dir$// if $Is_NT; + &finddir($wanted,$fixtopdir,$topnlink); + } } else { warn "Can't cd to $topdir: $!\n"; @@ -169,7 +173,8 @@ sub finddepth { # compatibility. local($topdir, $topdev, $topino, $topmode, $topnlink); foreach $topdir (@_) { - (($topdev,$topino,$topmode,$topnlink) = stat($topdir)) + (($topdev,$topino,$topmode,$topnlink) = + ($Is_VMS ? stat($topdir) : lstat($topdir))) || (warn("Can't stat $topdir: $!\n"), next); if (-d _) { if (chdir($topdir)) { @@ -190,6 +195,7 @@ sub finddepth { unless (($_,$dir) = File::Basename::fileparse($topdir)) { ($dir,$_) = ('.', $topdir); } + $name = $topdir; chdir $dir && &$wanted; } chdir $cwd;