ext/re/hints/MSWin32.pl seems to be missing from perlio.
[p5sagit/p5-mst-13.2.git] / lib / File / Find.pm
CommitLineData
a0d0e21e 1package File::Find;
17f410f9 2use 5.005_64;
a0d0e21e 3require Exporter;
6280b799 4require Cwd;
a0d0e21e 5
f06db76b 6=head1 NAME
7
8find - traverse a file tree
9
10finddepth - traverse a directory structure depth-first
11
12=head1 SYNOPSIS
13
14 use File::Find;
81793b90 15 find(\&wanted, '/foo', '/bar');
f06db76b 16 sub wanted { ... }
237437d0 17
f06db76b 18 use File::Find;
81793b90 19 finddepth(\&wanted, '/foo', '/bar');
f06db76b 20 sub wanted { ... }
3cb6de81 21
81793b90 22 use File::Find;
23 find({ wanted => \&process, follow => 1 }, '.');
f06db76b 24
25=head1 DESCRIPTION
26
20408e3c 27The first argument to find() is either a hash reference describing the
81793b90 28operations to be performed for each file, or a code reference.
20408e3c 29
81793b90 30Here are the possible keys for the hash:
31
32=over 3
33
34=item C<wanted>
35
36The value should be a code reference. This code reference is called
37I<the wanted() function> below.
38
39=item C<bydepth>
40
41Reports the name of a directory only AFTER all its entries
42have been reported. Entry point finddepth() is a shortcut for
43specifying C<{ bydepth => 1 }> in the first argument of find().
44
719c805e 45=item C<preprocess>
46
47The value should be a code reference. This code reference is used to
48preprocess a directory; it is called after readdir() but before the loop that
49calls the wanted() function. It is called with a list of strings and is
50expected to return a list of strings. The code can be used to sort the
51strings alphabetically, numerically, or to filter out directory entries based
52on their name alone.
53
54=item C<postprocess>
55
56The value should be a code reference. It is invoked just before leaving the
57current directory. It is called in void context with no arguments. The name
58of the current directory is in $File::Find::dir. This hook is handy for
59summarizing a directory, such as calculating its disk usage.
60
81793b90 61=item C<follow>
62
63Causes symbolic links to be followed. Since directory trees with symbolic
64links (followed) may contain files more than once and may even have
65cycles, a hash has to be built up with an entry for each file.
66This might be expensive both in space and time for a large
67directory tree. See I<follow_fast> and I<follow_skip> below.
68If either I<follow> or I<follow_fast> is in effect:
69
70=over 6
71
a45bd81d 72=item *
81793b90 73
f10e1564 74It is guaranteed that an I<lstat> has been called before the user's
81793b90 75I<wanted()> function is called. This enables fast file checks involving S< _>.
76
a45bd81d 77=item *
81793b90 78
79There is a variable C<$File::Find::fullname> which holds the absolute
80pathname of the file with all symbolic links resolved
81
82=back
83
84=item C<follow_fast>
85
f10e1564 86This is similar to I<follow> except that it may report some files more
87than once. It does detect cycles, however. Since only symbolic links
88have to be hashed, this is much cheaper both in space and time. If
89processing a file more than once (by the user's I<wanted()> function)
81793b90 90is worse than just taking time, the option I<follow> should be used.
91
92=item C<follow_skip>
93
94C<follow_skip==1>, which is the default, causes all files which are
95neither directories nor symbolic links to be ignored if they are about
96to be processed a second time. If a directory or a symbolic link
97are about to be processed a second time, File::Find dies.
98C<follow_skip==0> causes File::Find to die if any file is about to be
99processed a second time.
100C<follow_skip==2> causes File::Find to ignore any duplicate files and
101dirctories but to proceed normally otherwise.
20408e3c 102
f06db76b 103
81793b90 104=item C<no_chdir>
105
106Does not C<chdir()> to each directory as it recurses. The wanted()
107function will need to be aware of this, of course. In this case,
108C<$_> will be the same as C<$File::Find::name>.
109
110=item C<untaint>
111
112If find is used in taint-mode (-T command line switch or if EUID != UID
113or if EGID != GID) then internally directory names have to be untainted
114before they can be cd'ed to. Therefore they are checked against a regular
f10e1564 115expression I<untaint_pattern>. Note that all names passed to the
81793b90 116user's I<wanted()> function are still tainted.
117
118=item C<untaint_pattern>
119
120See above. This should be set using the C<qr> quoting operator.
121The default is set to C<qr|^([-+@\w./]+)$|>.
ac06ab1d 122Note that the parantheses are vital.
81793b90 123
124=item C<untaint_skip>
125
126If set, directories (subtrees) which fail the I<untaint_pattern>
127are skipped. The default is to 'die' in such a case.
128
129=back
130
131The wanted() function does whatever verifications you want.
132C<$File::Find::dir> contains the current directory name, and C<$_> the
133current filename within that directory. C<$File::Find::name> contains
f10e1564 134the complete pathname to the file. You are chdir()'d to
135C<$File::Find::dir> when the function is called, unless C<no_chdir>
136was specified. When <follow> or <follow_fast> are in effect, there is
137also a C<$File::Find::fullname>. The function may set
138C<$File::Find::prune> to prune the tree unless C<bydepth> was
139specified. Unless C<follow> or C<follow_fast> is specified, for
140compatibility reasons (find.pl, find2perl) there are in addition the
141following globals available: C<$File::Find::topdir>,
142C<$File::Find::topdev>, C<$File::Find::topino>,
e7b91b67 143C<$File::Find::topmode> and C<$File::Find::topnlink>.
47a735e8 144
20408e3c 145This library is useful for the C<find2perl> tool, which when fed,
f06db76b 146
147 find2perl / -name .nfs\* -mtime +7 \
81793b90 148 -exec rm -f {} \; -o -fstype nfs -prune
f06db76b 149
150produces something like:
151
152 sub wanted {
c7b9dd21 153 /^\.nfs.*\z/s &&
81793b90 154 (($dev, $ino, $mode, $nlink, $uid, $gid) = lstat($_)) &&
f06db76b 155 int(-M _) > 7 &&
156 unlink($_)
157 ||
81793b90 158 ($nlink || (($dev, $ino, $mode, $nlink, $uid, $gid) = lstat($_))) &&
f06db76b 159 $dev < 0 &&
6280b799 160 ($File::Find::prune = 1);
f06db76b 161 }
162
81793b90 163Set the variable C<$File::Find::dont_use_nlink> if you're using AFS,
6280b799 164since AFS cheats.
f06db76b 165
f06db76b 166
167Here's another interesting wanted function. It will find all symlinks
168that don't resolve:
169
170 sub wanted {
81793b90 171 -l && !-e && print "bogus link: $File::Find::name\n";
237437d0 172 }
f06db76b 173
81793b90 174See also the script C<pfind> on CPAN for a nice application of this
175module.
176
177=head1 CAVEAT
178
f10e1564 179Be aware that the option to follow symbolic links can be dangerous.
81793b90 180Depending on the structure of the directory tree (including symbolic
181links to directories) you might traverse a given (physical) directory
182more than once (only if C<follow_fast> is in effect).
183Furthermore, deleting or changing files in a symbolically linked directory
184might cause very unpleasant surprises, since you delete or change files
185in an unknown directory.
0530a6c4 186
0530a6c4 187
f06db76b 188=cut
189
a0d0e21e 190@ISA = qw(Exporter);
6280b799 191@EXPORT = qw(find finddepth);
192
a0d0e21e 193
81793b90 194use strict;
195my $Is_VMS;
196
197require File::Basename;
198
199my %SLnkSeen;
200my ($wanted_callback, $avoid_nlink, $bydepth, $no_chdir, $follow,
719c805e 201 $follow_skip, $full_check, $untaint, $untaint_skip, $untaint_pat,
202 $pre_process, $post_process);
81793b90 203
204sub contract_name {
205 my ($cdir,$fn) = @_;
206
207 return substr($cdir,0,rindex($cdir,'/')) if $fn eq '.';
208
209 $cdir = substr($cdir,0,rindex($cdir,'/')+1);
210
211 $fn =~ s|^\./||;
212
213 my $abs_name= $cdir . $fn;
214
215 if (substr($fn,0,3) eq '../') {
216 do 1 while ($abs_name=~ s|/(?>[^/]+)/\.\./|/|);
217 }
218
219 return $abs_name;
220}
221
222
223sub PathCombine($$) {
224 my ($Base,$Name) = @_;
225 my $AbsName;
226
227 if (substr($Name,0,1) eq '/') {
228 $AbsName= $Name;
229 }
230 else {
231 $AbsName= contract_name($Base,$Name);
232 }
233
234 # (simple) check for recursion
235 my $newlen= length($AbsName);
236 if ($newlen <= length($Base)) {
237 if (($newlen == length($Base) || substr($Base,$newlen,1) eq '/')
238 && $AbsName eq substr($Base,0,$newlen))
239 {
240 return undef;
241 }
242 }
243 return $AbsName;
244}
245
246sub Follow_SymLink($) {
247 my ($AbsName) = @_;
248
249 my ($NewName,$DEV, $INO);
250 ($DEV, $INO)= lstat $AbsName;
251
252 while (-l _) {
253 if ($SLnkSeen{$DEV, $INO}++) {
254 if ($follow_skip < 2) {
255 die "$AbsName is encountered a second time";
a0d0e21e 256 }
257 else {
81793b90 258 return undef;
a0d0e21e 259 }
260 }
81793b90 261 $NewName= PathCombine($AbsName, readlink($AbsName));
262 unless(defined $NewName) {
263 if ($follow_skip < 2) {
264 die "$AbsName is a recursive symbolic link";
265 }
266 else {
267 return undef;
a0d0e21e 268 }
81793b90 269 }
270 else {
271 $AbsName= $NewName;
272 }
273 ($DEV, $INO) = lstat($AbsName);
274 return undef unless defined $DEV; # dangling symbolic link
275 }
276
277 if ($full_check && $SLnkSeen{$DEV, $INO}++) {
278 if ($follow_skip < 1) {
279 die "$AbsName encountered a second time";
280 }
281 else {
282 return undef;
283 }
284 }
285
286 return $AbsName;
287}
288
17f410f9 289our($dir, $name, $fullname, $prune);
81793b90 290sub _find_dir_symlnk($$$);
291sub _find_dir($$$);
292
293sub _find_opt {
294 my $wanted = shift;
295 die "invalid top directory" unless defined $_[0];
296
297 my $cwd = $wanted->{bydepth} ? Cwd::fastcwd() : Cwd::cwd();
298 my $cwd_untainted = $cwd;
299 $wanted_callback = $wanted->{wanted};
300 $bydepth = $wanted->{bydepth};
719c805e 301 $pre_process = $wanted->{preprocess};
302 $post_process = $wanted->{postprocess};
81793b90 303 $no_chdir = $wanted->{no_chdir};
304 $full_check = $wanted->{follow};
305 $follow = $full_check || $wanted->{follow_fast};
306 $follow_skip = $wanted->{follow_skip};
307 $untaint = $wanted->{untaint};
308 $untaint_pat = $wanted->{untaint_pattern};
309 $untaint_skip = $wanted->{untaint_skip};
310
e7b91b67 311 # for compatability reasons (find.pl, find2perl)
312 our ($topdir, $topdev, $topino, $topmode, $topnlink);
81793b90 313
314 # a symbolic link to a directory doesn't increase the link count
315 $avoid_nlink = $follow || $File::Find::dont_use_nlink;
316
317 if ( $untaint ) {
318 $cwd_untainted= $1 if $cwd_untainted =~ m|$untaint_pat|;
319 die "insecure cwd in find(depth)" unless defined($cwd_untainted);
320 }
321
e7b91b67 322 my ($abs_dir, $Is_Dir);
81793b90 323
324 Proc_Top_Item:
325 foreach my $TOP (@_) {
326 my $top_item = $TOP;
c7b9dd21 327 $top_item =~ s|/\z|| unless $top_item eq '/';
81793b90 328 $Is_Dir= 0;
329
3d1e7443 330 ($topdev,$topino,$topmode,$topnlink) = stat $top_item;
331
81793b90 332 if ($follow) {
333 if (substr($top_item,0,1) eq '/') {
334 $abs_dir = $top_item;
335 }
336 elsif ($top_item eq '.') {
337 $abs_dir = $cwd;
237437d0 338 }
81793b90 339 else { # care about any ../
340 $abs_dir = contract_name("$cwd/",$top_item);
341 }
342 $abs_dir= Follow_SymLink($abs_dir);
343 unless (defined $abs_dir) {
344 warn "$top_item is a dangling symbolic link\n";
345 next Proc_Top_Item;
346 }
347 if (-d _) {
348 _find_dir_symlnk($wanted, $abs_dir, $top_item);
349 $Is_Dir= 1;
350 }
351 }
352 else { # no follow
e7b91b67 353 $topdir = $top_item;
e7b91b67 354 unless (defined $topnlink) {
81793b90 355 warn "Can't stat $top_item: $!\n";
356 next Proc_Top_Item;
357 }
358 if (-d _) {
c7b9dd21 359 $top_item =~ s/\.dir\z// if $Is_VMS;
e7b91b67 360 _find_dir($wanted, $top_item, $topnlink);
81793b90 361 $Is_Dir= 1;
362 }
237437d0 363 else {
81793b90 364 $abs_dir= $top_item;
365 }
366 }
367
368 unless ($Is_Dir) {
369 unless (($_,$dir) = File::Basename::fileparse($abs_dir)) {
719911cc 370 ($dir,$_) = ('./', $top_item);
81793b90 371 }
372
373 $abs_dir = $dir;
374 if ($untaint) {
375 my $abs_dir_save = $abs_dir;
376 $abs_dir = $1 if $abs_dir =~ m|$untaint_pat|;
377 unless (defined $abs_dir) {
378 if ($untaint_skip == 0) {
379 die "directory $abs_dir_save is still tainted";
380 }
381 else {
382 next Proc_Top_Item;
383 }
384 }
385 }
386
387 unless ($no_chdir or chdir $abs_dir) {
388 warn "Couldn't chdir $abs_dir: $!\n";
389 next Proc_Top_Item;
390 }
719911cc 391
392 $name = $abs_dir . $_;
393
73396e07 394 { &$wanted_callback }; # protect against wild "next"
81793b90 395
396 }
397
398 $no_chdir or chdir $cwd_untainted;
399 }
400}
401
402# API:
403# $wanted
404# $p_dir : "parent directory"
405# $nlink : what came back from the stat
406# preconditions:
407# chdir (if not no_chdir) to dir
408
409sub _find_dir($$$) {
410 my ($wanted, $p_dir, $nlink) = @_;
411 my ($CdLvl,$Level) = (0,0);
412 my @Stack;
413 my @filenames;
414 my ($subcount,$sub_nlink);
415 my $SE= [];
416 my $dir_name= $p_dir;
07867069 417 my $dir_pref= ( $p_dir eq '/' ? '/' : "$p_dir/" );
81793b90 418 my $dir_rel= '.'; # directory name relative to current directory
419
420 local ($dir, $name, $prune, *DIR);
421
422 unless ($no_chdir or $p_dir eq '.') {
423 my $udir = $p_dir;
424 if ($untaint) {
425 $udir = $1 if $p_dir =~ m|$untaint_pat|;
426 unless (defined $udir) {
427 if ($untaint_skip == 0) {
428 die "directory $p_dir is still tainted";
429 }
430 else {
431 return;
432 }
237437d0 433 }
a0d0e21e 434 }
81793b90 435 unless (chdir $udir) {
436 warn "Can't cd to $udir: $!\n";
437 return;
438 }
439 }
57e73c4b 440
441 push @Stack,[$CdLvl,$p_dir,$dir_rel,-1] if $bydepth;
81793b90 442
443 while (defined $SE) {
444 unless ($bydepth) {
445 $dir= $p_dir;
446 $name= $dir_name;
447 $_= ($no_chdir ? $dir_name : $dir_rel );
448 # prune may happen here
449 $prune= 0;
73396e07 450 { &$wanted_callback }; # protect against wild "next"
81793b90 451 next if $prune;
452 }
453
454 # change to that directory
455 unless ($no_chdir or $dir_rel eq '.') {
456 my $udir= $dir_rel;
457 if ($untaint) {
458 $udir = $1 if $dir_rel =~ m|$untaint_pat|;
459 unless (defined $udir) {
460 if ($untaint_skip == 0) {
07867069 461 die "directory ("
462 . ($p_dir ne '/' ? $p_dir : '')
463 . "/) $dir_rel is still tainted";
81793b90 464 }
465 }
466 }
467 unless (chdir $udir) {
07867069 468 warn "Can't cd to ("
469 . ($p_dir ne '/' ? $p_dir : '')
470 . "/) $udir : $!\n";
81793b90 471 next;
472 }
473 $CdLvl++;
474 }
475
476 $dir= $dir_name;
477
478 # Get the list of files in the current directory.
479 unless (opendir DIR, ($no_chdir ? $dir_name : '.')) {
480 warn "Can't opendir($dir_name): $!\n";
481 next;
482 }
483 @filenames = readdir DIR;
484 closedir(DIR);
719c805e 485 @filenames = &$pre_process(@filenames) if $pre_process;
486 push @Stack,[$CdLvl,$dir_name,"",-2] if $post_process;
81793b90 487
488 if ($nlink == 2 && !$avoid_nlink) {
489 # This dir has no subdirectories.
490 for my $FN (@filenames) {
c7b9dd21 491 next if $FN =~ /^\.{1,2}\z/;
81793b90 492
07867069 493 $name = $dir_pref . $FN;
81793b90 494 $_ = ($no_chdir ? $name : $FN);
73396e07 495 { &$wanted_callback }; # protect against wild "next"
81793b90 496 }
497
498 }
499 else {
500 # This dir has subdirectories.
501 $subcount = $nlink - 2;
502
503 for my $FN (@filenames) {
c7b9dd21 504 next if $FN =~ /^\.{1,2}\z/;
81793b90 505 if ($subcount > 0 || $avoid_nlink) {
506 # Seen all the subdirs?
507 # check for directoriness.
508 # stat is faster for a file in the current directory
07867069 509 $sub_nlink = (lstat ($no_chdir ? $dir_pref . $FN : $FN))[3];
81793b90 510
511 if (-d _) {
512 --$subcount;
c7b9dd21 513 $FN =~ s/\.dir\z// if $Is_VMS;
81793b90 514 push @Stack,[$CdLvl,$dir_name,$FN,$sub_nlink];
515 }
516 else {
07867069 517 $name = $dir_pref . $FN;
81793b90 518 $_= ($no_chdir ? $name : $FN);
73396e07 519 { &$wanted_callback }; # protect against wild "next"
81793b90 520 }
521 }
07867069 522 else {
523 $name = $dir_pref . $FN;
81793b90 524 $_= ($no_chdir ? $name : $FN);
73396e07 525 { &$wanted_callback }; # protect against wild "next"
81793b90 526 }
527 }
528 }
17b275ff 529 }
530 continue {
57e73c4b 531 while ( defined ($SE = pop @Stack) ) {
81793b90 532 ($Level, $p_dir, $dir_rel, $nlink) = @$SE;
533 if ($CdLvl > $Level && !$no_chdir) {
f0963acb 534 my $tmp = join('/',('..') x ($CdLvl-$Level));
535 die "Can't cd to $dir_name" . $tmp
536 unless chdir ($tmp);
81793b90 537 $CdLvl = $Level;
538 }
07867069 539 $dir_name = ($p_dir eq '/' ? "/$dir_rel" : "$p_dir/$dir_rel");
540 $dir_pref = "$dir_name/";
719c805e 541 if ( $nlink == -2 ) {
542 $name = $dir = $p_dir;
543 $_ = ".";
544 &$post_process; # End-of-directory processing
545 } elsif ( $nlink < 0 ) { # must be finddepth, report dirname now
57e73c4b 546 $name = $dir_name;
57907763 547 if ( substr($name,-2) eq '/.' ) {
548 $name =~ s|/\.$||;
549 }
57e73c4b 550 $dir = $p_dir;
551 $_ = ($no_chdir ? $dir_name : $dir_rel );
57907763 552 if ( substr($_,-2) eq '/.' ) {
553 s|/\.$||;
554 }
73396e07 555 { &$wanted_callback }; # protect against wild "next"
57e73c4b 556 } else {
557 push @Stack,[$CdLvl,$p_dir,$dir_rel,-1] if $bydepth;
558 last;
559 }
81793b90 560 }
a0d0e21e 561 }
562}
563
81793b90 564
565# API:
566# $wanted
567# $dir_loc : absolute location of a dir
568# $p_dir : "parent directory"
569# preconditions:
570# chdir (if not no_chdir) to dir
571
572sub _find_dir_symlnk($$$) {
573 my ($wanted, $dir_loc, $p_dir) = @_;
574 my @Stack;
575 my @filenames;
576 my $new_loc;
57e73c4b 577 my $pdir_loc = $dir_loc;
81793b90 578 my $SE = [];
579 my $dir_name = $p_dir;
07867069 580 my $dir_pref = ( $p_dir eq '/' ? '/' : "$p_dir/" );
581 my $loc_pref = ( $dir_loc eq '/' ? '/' : "$dir_loc/" );
81793b90 582 my $dir_rel = '.'; # directory name relative to current directory
57e73c4b 583 my $byd_flag; # flag for pending stack entry if $bydepth
81793b90 584
585 local ($dir, $name, $fullname, $prune, *DIR);
586
587 unless ($no_chdir or $p_dir eq '.') {
588 my $udir = $dir_loc;
589 if ($untaint) {
590 $udir = $1 if $dir_loc =~ m|$untaint_pat|;
591 unless (defined $udir) {
592 if ($untaint_skip == 0) {
593 die "directory $dir_loc is still tainted";
594 }
595 else {
596 return;
597 }
598 }
599 }
600 unless (chdir $udir) {
601 warn "Can't cd to $udir: $!\n";
602 return;
603 }
604 }
605
57e73c4b 606 push @Stack,[$dir_loc,$pdir_loc,$p_dir,$dir_rel,-1] if $bydepth;
607
81793b90 608 while (defined $SE) {
609
610 unless ($bydepth) {
704ea872 611 # change to parent directory
612 unless ($no_chdir) {
613 my $udir = $pdir_loc;
614 if ($untaint) {
615 $udir = $1 if $pdir_loc =~ m|$untaint_pat|;
616 }
617 unless (chdir $udir) {
618 warn "Can't cd to $udir: $!\n";
619 next;
620 }
621 }
81793b90 622 $dir= $p_dir;
623 $name= $dir_name;
624 $_= ($no_chdir ? $dir_name : $dir_rel );
625 $fullname= $dir_loc;
626 # prune may happen here
627 $prune= 0;
704ea872 628 lstat($_); # make sure file tests with '_' work
73396e07 629 { &$wanted_callback }; # protect against wild "next"
81793b90 630 next if $prune;
631 }
632
633 # change to that directory
634 unless ($no_chdir or $dir_rel eq '.') {
635 my $udir = $dir_loc;
636 if ($untaint) {
637 $udir = $1 if $dir_loc =~ m|$untaint_pat|;
638 unless (defined $udir ) {
639 if ($untaint_skip == 0) {
640 die "directory $dir_loc is still tainted";
a0d0e21e 641 }
237437d0 642 else {
81793b90 643 next;
237437d0 644 }
a0d0e21e 645 }
646 }
81793b90 647 unless (chdir $udir) {
648 warn "Can't cd to $udir: $!\n";
649 next;
650 }
651 }
652
653 $dir = $dir_name;
654
655 # Get the list of files in the current directory.
656 unless (opendir DIR, ($no_chdir ? $dir_loc : '.')) {
657 warn "Can't opendir($dir_loc): $!\n";
658 next;
659 }
660 @filenames = readdir DIR;
661 closedir(DIR);
662
663 for my $FN (@filenames) {
c7b9dd21 664 next if $FN =~ /^\.{1,2}\z/;
81793b90 665
666 # follow symbolic links / do an lstat
07867069 667 $new_loc = Follow_SymLink($loc_pref.$FN);
81793b90 668
669 # ignore if invalid symlink
670 next unless defined $new_loc;
671
672 if (-d _) {
57e73c4b 673 push @Stack,[$new_loc,$dir_loc,$dir_name,$FN,1];
81793b90 674 }
675 else {
676 $fullname = $new_loc;
07867069 677 $name = $dir_pref . $FN;
81793b90 678 $_ = ($no_chdir ? $name : $FN);
73396e07 679 { &$wanted_callback }; # protect against wild "next"
81793b90 680 }
681 }
682
81793b90 683 }
684 continue {
57e73c4b 685 while (defined($SE = pop @Stack)) {
686 ($dir_loc, $pdir_loc, $p_dir, $dir_rel, $byd_flag) = @$SE;
07867069 687 $dir_name = ($p_dir eq '/' ? "/$dir_rel" : "$p_dir/$dir_rel");
688 $dir_pref = "$dir_name/";
689 $loc_pref = "$dir_loc/";
57e73c4b 690 if ( $byd_flag < 0 ) { # must be finddepth, report dirname now
691 unless ($no_chdir or $dir_rel eq '.') {
692 my $udir = $pdir_loc;
693 if ($untaint) {
694 $udir = $1 if $dir_loc =~ m|$untaint_pat|;
695 }
696 unless (chdir $udir) {
697 warn "Can't cd to $udir: $!\n";
698 next;
699 }
700 }
701 $fullname = $dir_loc;
702 $name = $dir_name;
57907763 703 if ( substr($name,-2) eq '/.' ) {
704 $name =~ s|/\.$||;
705 }
57e73c4b 706 $dir = $p_dir;
707 $_ = ($no_chdir ? $dir_name : $dir_rel);
57907763 708 if ( substr($_,-2) eq '/.' ) {
709 s|/\.$||;
710 }
711
704ea872 712 lstat($_); # make sure file tests with '_' work
73396e07 713 { &$wanted_callback }; # protect against wild "next"
57e73c4b 714 } else {
715 push @Stack,[$dir_loc, $pdir_loc, $p_dir, $dir_rel,-1] if $bydepth;
716 last;
717 }
a0d0e21e 718 }
719 }
720}
721
81793b90 722
20408e3c 723sub wrap_wanted {
81793b90 724 my $wanted = shift;
725 if ( ref($wanted) eq 'HASH' ) {
726 if ( $wanted->{follow} || $wanted->{follow_fast}) {
727 $wanted->{follow_skip} = 1 unless defined $wanted->{follow_skip};
728 }
729 if ( $wanted->{untaint} ) {
730 $wanted->{untaint_pattern} = qr|^([-+@\w./]+)$|
731 unless defined $wanted->{untaint_pattern};
732 $wanted->{untaint_skip} = 0 unless defined $wanted->{untaint_skip};
733 }
734 return $wanted;
735 }
736 else {
737 return { wanted => $wanted };
738 }
a0d0e21e 739}
740
20408e3c 741sub find {
81793b90 742 my $wanted = shift;
743 _find_opt(wrap_wanted($wanted), @_);
744 %SLnkSeen= (); # free memory
a0d0e21e 745}
746
55d729e4 747sub finddepth {
81793b90 748 my $wanted = wrap_wanted(shift);
749 $wanted->{bydepth} = 1;
750 _find_opt($wanted, @_);
751 %SLnkSeen= (); # free memory
20408e3c 752}
6280b799 753
754# These are hard-coded for now, but may move to hint files.
10eba763 755if ($^O eq 'VMS') {
81793b90 756 $Is_VMS = 1;
757 $File::Find::dont_use_nlink = 1;
748a9306 758}
759
81793b90 760$File::Find::dont_use_nlink = 1
497711e7 761 if $^O eq 'os2' || $^O eq 'dos' || $^O eq 'amigaos' || $^O eq 'MSWin32' ||
762 $^O eq 'cygwin';
6280b799 763
20408e3c 764# Set dont_use_nlink in your hint file if your system's stat doesn't
765# report the number of links in a directory as an indication
766# of the number of files.
767# See, e.g. hints/machten.sh for MachTen 2.2.
81793b90 768unless ($File::Find::dont_use_nlink) {
769 require Config;
770 $File::Find::dont_use_nlink = 1 if ($Config::Config{'dont_use_nlink'});
20408e3c 771}
772
a0d0e21e 7731;