This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
Re: [perl #36502] File::Copy::mv fails to replicate behavior of Unix mv
[perl5.git] / lib / File / Find.pm
CommitLineData
a0d0e21e 1package File::Find;
3b825e41 2use 5.006;
b75c8c73 3use strict;
b395063c 4use warnings;
cd68ec93 5use warnings::register;
3555aed3 6our $VERSION = '1.10';
a0d0e21e 7require Exporter;
6280b799 8require Cwd;
a0d0e21e 9
7bd31527
JH
10#
11# Modified to ensure sub-directory traversal order is not inverded by stack
12# push and pops. That is remains in the same order as in the directory file,
13# or user pre-processing (EG:sorted).
14#
15
f06db76b
AD
16=head1 NAME
17
abfdd623 18File::Find - Traverse a directory tree.
f06db76b
AD
19
20=head1 SYNOPSIS
21
22 use File::Find;
6d355c6e 23 find(\&wanted, @directories_to_search);
f06db76b 24 sub wanted { ... }
237437d0 25
f06db76b 26 use File::Find;
abfdd623 27 finddepth(\&wanted, @directories_to_search);
f06db76b 28 sub wanted { ... }
3cb6de81 29
81793b90
GS
30 use File::Find;
31 find({ wanted => \&process, follow => 1 }, '.');
f06db76b
AD
32
33=head1 DESCRIPTION
34
abfdd623
MS
35These are functions for searching through directory trees doing work
36on each file found similar to the Unix I<find> command. File::Find
37exports two functions, C<find> and C<finddepth>. They work similarly
38but have subtle differences.
39
40=over 4
41
42=item B<find>
43
44 find(\&wanted, @directories);
45 find(\%options, @directories);
46
6eb87ff8
MJD
47C<find()> does a depth-first search over the given C<@directories> in
48the order they are given. For each file or directory found, it calls
49the C<&wanted> subroutine. (See below for details on how to use the
50C<&wanted> function). Additionally, for each directory found, it will
51C<chdir()> into that directory and continue the search, invoking the
52C<&wanted> function on each file or subdirectory in the directory.
abfdd623
MS
53
54=item B<finddepth>
55
56 finddepth(\&wanted, @directories);
57 finddepth(\%options, @directories);
58
6eb87ff8
MJD
59C<finddepth()> works just like C<find()> except that is invokes the
60C<&wanted> function for a directory I<after> invoking it for the
61directory's contents. It does a postorder traversal instead of a
62preorder traversal, working from the bottom of the directory tree up
63where C<find()> works from the top of the tree down.
abfdd623
MS
64
65=back
66
67=head2 %options
68
95e23d19
AL
69The first argument to C<find()> is either a code reference to your
70C<&wanted> function, or a hash reference describing the operations
71to be performed for each file. The
abfdd623 72code reference is described in L<The wanted function> below.
20408e3c 73
81793b90
GS
74Here are the possible keys for the hash:
75
76=over 3
77
78=item C<wanted>
79
abfdd623
MS
80The value should be a code reference. This code reference is
81described in L<The wanted function> below.
81793b90
GS
82
83=item C<bydepth>
84
85Reports the name of a directory only AFTER all its entries
95e23d19
AL
86have been reported. Entry point C<finddepth()> is a shortcut for
87specifying C<<{ bydepth => 1 }>> in the first argument of C<find()>.
81793b90 88
719c805e
JS
89=item C<preprocess>
90
3555aed3
SP
91The value should be a code reference. This code reference is used to
92preprocess the current directory. The name of the currently processed
95e23d19
AL
93directory is in C<$File::Find::dir>. Your preprocessing function is
94called after C<readdir()>, but before the loop that calls the C<wanted()>
3555aed3
SP
95function. It is called with a list of strings (actually file/directory
96names) and is expected to return a list of strings. The code can be
97used to sort the file/directory names alphabetically, numerically,
98or to filter out directory entries based on their name alone. When
7e47e6ff 99I<follow> or I<follow_fast> are in effect, C<preprocess> is a no-op.
719c805e
JS
100
101=item C<postprocess>
102
3555aed3
SP
103The value should be a code reference. It is invoked just before leaving
104the currently processed directory. It is called in void context with no
105arguments. The name of the current directory is in C<$File::Find::dir>. This
106hook is handy for summarizing a directory, such as calculating its disk
107usage. When I<follow> or I<follow_fast> are in effect, C<postprocess> is a
7e47e6ff 108no-op.
719c805e 109
81793b90
GS
110=item C<follow>
111
112Causes symbolic links to be followed. Since directory trees with symbolic
113links (followed) may contain files more than once and may even have
114cycles, a hash has to be built up with an entry for each file.
115This might be expensive both in space and time for a large
116directory tree. See I<follow_fast> and I<follow_skip> below.
117If either I<follow> or I<follow_fast> is in effect:
118
119=over 6
120
a45bd81d 121=item *
81793b90 122
f10e1564 123It is guaranteed that an I<lstat> has been called before the user's
95e23d19 124C<wanted()> function is called. This enables fast file checks involving S< _>.
81793b90 125
a45bd81d 126=item *
81793b90
GS
127
128There is a variable C<$File::Find::fullname> which holds the absolute
615a2b9b
SP
129pathname of the file with all symbolic links resolved. If the link is
130a dangling symbolic link, then fullname will be set to C<undef>.
81793b90
GS
131
132=back
133
134=item C<follow_fast>
135
f10e1564
RM
136This is similar to I<follow> except that it may report some files more
137than once. It does detect cycles, however. Since only symbolic links
138have to be hashed, this is much cheaper both in space and time. If
95e23d19 139processing a file more than once (by the user's C<wanted()> function)
81793b90
GS
140is worse than just taking time, the option I<follow> should be used.
141
142=item C<follow_skip>
143
144C<follow_skip==1>, which is the default, causes all files which are
145neither directories nor symbolic links to be ignored if they are about
3555aed3 146to be processed a second time. If a directory or a symbolic link
81793b90 147are about to be processed a second time, File::Find dies.
95e23d19 148
81793b90
GS
149C<follow_skip==0> causes File::Find to die if any file is about to be
150processed a second time.
95e23d19 151
81793b90 152C<follow_skip==2> causes File::Find to ignore any duplicate files and
7e47e6ff 153directories but to proceed normally otherwise.
20408e3c 154
80e52b73
JH
155=item C<dangling_symlinks>
156
157If true and a code reference, will be called with the symbolic link
158name and the directory it lives in as arguments. Otherwise, if true
159and warnings are on, warning "symbolic_link_name is a dangling
160symbolic link\n" will be issued. If false, the dangling symbolic link
161will be silently ignored.
f06db76b 162
81793b90
GS
163=item C<no_chdir>
164
95e23d19 165Does not C<chdir()> to each directory as it recurses. The C<wanted()>
81793b90
GS
166function will need to be aware of this, of course. In this case,
167C<$_> will be the same as C<$File::Find::name>.
168
169=item C<untaint>
170
171If find is used in taint-mode (-T command line switch or if EUID != UID
172or if EGID != GID) then internally directory names have to be untainted
7e47e6ff 173before they can be chdir'ed to. Therefore they are checked against a regular
3555aed3
SP
174expression I<untaint_pattern>. Note that all names passed to the user's
175I<wanted()> function are still tainted. If this option is used while
7e47e6ff 176not in taint-mode, C<untaint> is a no-op.
81793b90
GS
177
178=item C<untaint_pattern>
179
180See above. This should be set using the C<qr> quoting operator.
3555aed3 181The default is set to C<qr|^([-+@\w./]+)$|>.
1cffc1dd 182Note that the parentheses are vital.
81793b90
GS
183
184=item C<untaint_skip>
185
3555aed3 186If set, a directory which fails the I<untaint_pattern> is skipped,
7e47e6ff 187including all its sub-directories. The default is to 'die' in such a case.
81793b90
GS
188
189=back
190
abfdd623
MS
191=head2 The wanted function
192
95e23d19
AL
193The C<wanted()> function does whatever verifications you want on
194each file and directory. Note that despite its name, the C<wanted()>
195function is a generic callback function, and does B<not> tell
196File::Find if a file is "wanted" or not. In fact, its return value
197is ignored.
198
199The wanted function takes no arguments but rather does its work
abfdd623
MS
200through a collection of variables.
201
202=over 4
203
f837ebe2 204=item C<$File::Find::dir> is the current directory name,
abfdd623
MS
205
206=item C<$_> is the current filename within that directory
207
f837ebe2 208=item C<$File::Find::name> is the complete pathname to the file.
abfdd623
MS
209
210=back
211
f837ebe2
MS
212Don't modify these variables.
213
95e23d19 214For example, when examining the file F</some/path/foo.ext> you will have:
abfdd623
MS
215
216 $File::Find::dir = /some/path/
217 $_ = foo.ext
218 $File::Find::name = /some/path/foo.ext
219
3555aed3 220You are chdir()'d to C<$File::Find::dir> when the function is called,
abfdd623
MS
221unless C<no_chdir> was specified. Note that when changing to
222directories is in effect the root directory (F</>) is a somewhat
223special case inasmuch as the concatenation of C<$File::Find::dir>,
224C<'/'> and C<$_> is not literally equal to C<$File::Find::name>. The
225table below summarizes all variants:
5cf0a2f2
WL
226
227 $File::Find::name $File::Find::dir $_
228 default / / .
229 no_chdir=>0 /etc / etc
230 /etc/x /etc x
abfdd623 231
5cf0a2f2
WL
232 no_chdir=>1 / / /
233 /etc / /etc
234 /etc/x /etc /etc/x
235
236
237When <follow> or <follow_fast> are in effect, there is
f10e1564
RM
238also a C<$File::Find::fullname>. The function may set
239C<$File::Find::prune> to prune the tree unless C<bydepth> was
240specified. Unless C<follow> or C<follow_fast> is specified, for
241compatibility reasons (find.pl, find2perl) there are in addition the
242following globals available: C<$File::Find::topdir>,
243C<$File::Find::topdev>, C<$File::Find::topino>,
e7b91b67 244C<$File::Find::topmode> and C<$File::Find::topnlink>.
47a735e8 245
20408e3c 246This library is useful for the C<find2perl> tool, which when fed,
f06db76b
AD
247
248 find2perl / -name .nfs\* -mtime +7 \
81793b90 249 -exec rm -f {} \; -o -fstype nfs -prune
f06db76b
AD
250
251produces something like:
252
253 sub wanted {
c7b9dd21 254 /^\.nfs.*\z/s &&
81793b90 255 (($dev, $ino, $mode, $nlink, $uid, $gid) = lstat($_)) &&
f06db76b
AD
256 int(-M _) > 7 &&
257 unlink($_)
258 ||
81793b90 259 ($nlink || (($dev, $ino, $mode, $nlink, $uid, $gid) = lstat($_))) &&
f06db76b 260 $dev < 0 &&
6280b799 261 ($File::Find::prune = 1);
f06db76b
AD
262 }
263
43dece2a
JH
264Notice the C<_> in the above C<int(-M _)>: the C<_> is a magical
265filehandle that caches the information from the preceding
95e23d19 266C<stat()>, C<lstat()>, or filetest.
43dece2a 267
1cffc1dd
JH
268Here's another interesting wanted function. It will find all symbolic
269links that don't resolve:
f06db76b
AD
270
271 sub wanted {
81793b90 272 -l && !-e && print "bogus link: $File::Find::name\n";
237437d0 273 }
f06db76b 274
81793b90
GS
275See also the script C<pfind> on CPAN for a nice application of this
276module.
277
cd68ec93
RGS
278=head1 WARNINGS
279
280If you run your program with the C<-w> switch, or if you use the
281C<warnings> pragma, File::Find will report warnings for several weird
282situations. You can disable these warnings by putting the statement
283
284 no warnings 'File::Find';
285
286in the appropriate scope. See L<perllexwarn> for more info about lexical
287warnings.
288
81793b90
GS
289=head1 CAVEAT
290
5fa2bf2b
DD
291=over 2
292
293=item $dont_use_nlink
294
295You can set the variable C<$File::Find::dont_use_nlink> to 1, if you want to
6cf3b067
T
296force File::Find to always stat directories. This was used for file systems
297that do not have an C<nlink> count matching the number of sub-directories.
298Examples are ISO-9660 (CD-ROM), AFS, HPFS (OS/2 file system), FAT (DOS file
299system) and a couple of others.
5fa2bf2b 300
6cf3b067
T
301You shouldn't need to set this variable, since File::Find should now detect
302such file systems on-the-fly and switch itself to using stat. This works even
303for parts of your file system, like a mounted CD-ROM.
5fa2bf2b 304
6cf3b067 305If you do set C<$File::Find::dont_use_nlink> to 1, you will notice slow-downs.
5fa2bf2b
DD
306
307=item symlinks
308
f10e1564 309Be aware that the option to follow symbolic links can be dangerous.
81793b90
GS
310Depending on the structure of the directory tree (including symbolic
311links to directories) you might traverse a given (physical) directory
3555aed3 312more than once (only if C<follow_fast> is in effect).
81793b90
GS
313Furthermore, deleting or changing files in a symbolically linked directory
314might cause very unpleasant surprises, since you delete or change files
315in an unknown directory.
0530a6c4 316
5fa2bf2b
DD
317=back
318
7e47e6ff
JH
319=head1 NOTES
320
321=over 4
322
323=item *
324
325Mac OS (Classic) users should note a few differences:
326
327=over 4
328
3555aed3 329=item *
7e47e6ff 330
3555aed3
SP
331The path separator is ':', not '/', and the current directory is denoted
332as ':', not '.'. You should be careful about specifying relative pathnames.
333While a full path always begins with a volume name, a relative pathname
334should always begin with a ':'. If specifying a volume name only, a
7e47e6ff
JH
335trailing ':' is required.
336
3555aed3 337=item *
7e47e6ff 338
3555aed3
SP
339C<$File::Find::dir> is guaranteed to end with a ':'. If C<$_>
340contains the name of a directory, that name may or may not end with a
341':'. Likewise, C<$File::Find::name>, which contains the complete
342pathname to that directory, and C<$File::Find::fullname>, which holds
7e47e6ff
JH
343the absolute pathname of that directory with all symbolic links resolved,
344may or may not end with a ':'.
345
3555aed3 346=item *
7e47e6ff 347
3555aed3 348The default C<untaint_pattern> (see above) on Mac OS is set to
7e47e6ff
JH
349C<qr|^(.+)$|>. Note that the parentheses are vital.
350
3555aed3 351=item *
7e47e6ff 352
3555aed3
SP
353The invisible system file "Icon\015" is ignored. While this file may
354appear in every directory, there are some more invisible system files
355on every volume, which are all located at the volume root level (i.e.
356"MacintoshHD:"). These system files are B<not> excluded automatically.
357Your filter may use the following code to recognize invisible files or
7e47e6ff
JH
358directories (requires Mac::Files):
359
360 use Mac::Files;
361
3555aed3 362 # invisible() -- returns 1 if file/directory is invisible,
1cffc1dd 363 # 0 if it's visible or undef if an error occurred
7e47e6ff 364
3555aed3 365 sub invisible($) {
7e47e6ff 366 my $file = shift;
3555aed3
SP
367 my ($fileCat, $fileInfo);
368 my $invisible_flag = 1 << 14;
7e47e6ff
JH
369
370 if ( $fileCat = FSpGetCatInfo($file) ) {
371 if ($fileInfo = $fileCat->ioFlFndrInfo() ) {
372 return (($fileInfo->fdFlags & $invisible_flag) && 1);
373 }
374 }
375 return undef;
376 }
377
3555aed3
SP
378Generally, invisible files are system files, unless an odd application
379decides to use invisible files for its own purposes. To distinguish
380such files from system files, you have to look at the B<type> and B<creator>
381file attributes. The MacPerl built-in functions C<GetFileInfo(FILE)> and
382C<SetFileInfo(CREATOR, TYPE, FILES)> offer access to these attributes
7e47e6ff
JH
383(see MacPerl.pm for details).
384
385Files that appear on the desktop actually reside in an (hidden) directory
386named "Desktop Folder" on the particular disk volume. Note that, although
3555aed3 387all desktop files appear to be on the same "virtual" desktop, each disk
7e47e6ff
JH
388volume actually maintains its own "Desktop Folder" directory.
389
390=back
391
392=back
0530a6c4 393
6eb87ff8
MJD
394=head1 BUGS AND CAVEATS
395
396Despite the name of the C<finddepth()> function, both C<find()> and
397C<finddepth()> perform a depth-first search of the directory
398hierarchy.
399
a85af077
A
400=head1 HISTORY
401
402File::Find used to produce incorrect results if called recursively.
403During the development of perl 5.8 this bug was fixed.
404The first fixed version of File::Find was 1.01.
405
f06db76b
AD
406=cut
407
b75c8c73
MS
408our @ISA = qw(Exporter);
409our @EXPORT = qw(find finddepth);
6280b799 410
a0d0e21e 411
81793b90
GS
412use strict;
413my $Is_VMS;
7e47e6ff 414my $Is_MacOS;
81793b90
GS
415
416require File::Basename;
7e47e6ff 417require File::Spec;
81793b90 418
9f826d6a
BM
419# Should ideally be my() not our() but local() currently
420# refuses to operate on lexicals
421
422our %SLnkSeen;
423our ($wanted_callback, $avoid_nlink, $bydepth, $no_chdir, $follow,
719c805e 424 $follow_skip, $full_check, $untaint, $untaint_skip, $untaint_pat,
80e52b73 425 $pre_process, $post_process, $dangling_symlinks);
81793b90
GS
426
427sub contract_name {
428 my ($cdir,$fn) = @_;
429
7e47e6ff 430 return substr($cdir,0,rindex($cdir,'/')) if $fn eq $File::Find::current_dir;
81793b90
GS
431
432 $cdir = substr($cdir,0,rindex($cdir,'/')+1);
433
434 $fn =~ s|^\./||;
435
436 my $abs_name= $cdir . $fn;
437
438 if (substr($fn,0,3) eq '../') {
fecbda2b 439 1 while $abs_name =~ s!/[^/]*/\.\./!/!;
81793b90
GS
440 }
441
442 return $abs_name;
443}
444
7e47e6ff
JH
445# return the absolute name of a directory or file
446sub contract_name_Mac {
3555aed3 447 my ($cdir,$fn) = @_;
7e47e6ff
JH
448 my $abs_name;
449
450 if ($fn =~ /^(:+)(.*)$/) { # valid pathname starting with a ':'
451
452 my $colon_count = length ($1);
453 if ($colon_count == 1) {
454 $abs_name = $cdir . $2;
455 return $abs_name;
456 }
3555aed3
SP
457 else {
458 # need to move up the tree, but
7e47e6ff
JH
459 # only if it's not a volume name
460 for (my $i=1; $i<$colon_count; $i++) {
461 unless ($cdir =~ /^[^:]+:$/) { # volume name
462 $cdir =~ s/[^:]+:$//;
463 }
464 else {
465 return undef;
466 }
467 }
468 $abs_name = $cdir . $2;
469 return $abs_name;
470 }
471
472 }
473 else {
474
475 # $fn may be a valid path to a directory or file or (dangling)
476 # symlink, without a leading ':'
477 if ( (-e $fn) || (-l $fn) ) {
478 if ($fn =~ /^[^:]+:/) { # a volume name like DataHD:*
479 return $fn; # $fn is already an absolute path
480 }
481 else {
482 $abs_name = $cdir . $fn;
483 return $abs_name;
484 }
485 }
3555aed3 486 else { # argh!, $fn is not a valid directory/file
7e47e6ff
JH
487 return undef;
488 }
489 }
490}
81793b90
GS
491
492sub PathCombine($$) {
493 my ($Base,$Name) = @_;
494 my $AbsName;
495
7e47e6ff
JH
496 if ($Is_MacOS) {
497 # $Name is the resolved symlink (always a full path on MacOS),
498 # i.e. there's no need to call contract_name_Mac()
3555aed3 499 $AbsName = $Name;
7e47e6ff
JH
500
501 # (simple) check for recursion
502 if ( ( $Base =~ /^$AbsName/) && (-d $AbsName) ) { # recursion
503 return undef;
504 }
81793b90
GS
505 }
506 else {
7e47e6ff
JH
507 if (substr($Name,0,1) eq '/') {
508 $AbsName= $Name;
509 }
510 else {
511 $AbsName= contract_name($Base,$Name);
512 }
81793b90 513
7e47e6ff
JH
514 # (simple) check for recursion
515 my $newlen= length($AbsName);
516 if ($newlen <= length($Base)) {
517 if (($newlen == length($Base) || substr($Base,$newlen,1) eq '/')
518 && $AbsName eq substr($Base,0,$newlen))
519 {
520 return undef;
521 }
81793b90
GS
522 }
523 }
524 return $AbsName;
525}
526
527sub Follow_SymLink($) {
528 my ($AbsName) = @_;
529
530 my ($NewName,$DEV, $INO);
531 ($DEV, $INO)= lstat $AbsName;
532
533 while (-l _) {
534 if ($SLnkSeen{$DEV, $INO}++) {
535 if ($follow_skip < 2) {
536 die "$AbsName is encountered a second time";
a0d0e21e
LW
537 }
538 else {
81793b90 539 return undef;
a0d0e21e
LW
540 }
541 }
81793b90
GS
542 $NewName= PathCombine($AbsName, readlink($AbsName));
543 unless(defined $NewName) {
544 if ($follow_skip < 2) {
545 die "$AbsName is a recursive symbolic link";
546 }
547 else {
548 return undef;
a0d0e21e 549 }
81793b90
GS
550 }
551 else {
552 $AbsName= $NewName;
553 }
554 ($DEV, $INO) = lstat($AbsName);
555 return undef unless defined $DEV; # dangling symbolic link
556 }
557
cd68ec93 558 if ($full_check && defined $DEV && $SLnkSeen{$DEV, $INO}++) {
7e47e6ff 559 if ( ($follow_skip < 1) || ((-d _) && ($follow_skip < 2)) ) {
81793b90
GS
560 die "$AbsName encountered a second time";
561 }
562 else {
563 return undef;
564 }
565 }
566
567 return $AbsName;
568}
569
17f410f9 570our($dir, $name, $fullname, $prune);
81793b90
GS
571sub _find_dir_symlnk($$$);
572sub _find_dir($$$);
573
7e47e6ff
JH
574# check whether or not a scalar variable is tainted
575# (code straight from the Camel, 3rd ed., page 561)
576sub is_tainted_pp {
577 my $arg = shift;
578 my $nada = substr($arg, 0, 0); # zero-length
579 local $@;
580 eval { eval "# $nada" };
581 return length($@) != 0;
3555aed3 582}
7e47e6ff 583
81793b90
GS
584sub _find_opt {
585 my $wanted = shift;
586 die "invalid top directory" unless defined $_[0];
587
9f826d6a
BM
588 # This function must local()ize everything because callbacks may
589 # call find() or finddepth()
590
591 local %SLnkSeen;
592 local ($wanted_callback, $avoid_nlink, $bydepth, $no_chdir, $follow,
593 $follow_skip, $full_check, $untaint, $untaint_skip, $untaint_pat,
80e52b73 594 $pre_process, $post_process, $dangling_symlinks);
4c621faf 595 local($dir, $name, $fullname, $prune);
bc125c03 596 local *_ = \my $a;
9f826d6a 597
a0c9c202 598 my $cwd = $wanted->{bydepth} ? Cwd::fastcwd() : Cwd::getcwd();
80e52b73
JH
599 my $cwd_untainted = $cwd;
600 my $check_t_cwd = 1;
601 $wanted_callback = $wanted->{wanted};
602 $bydepth = $wanted->{bydepth};
603 $pre_process = $wanted->{preprocess};
604 $post_process = $wanted->{postprocess};
605 $no_chdir = $wanted->{no_chdir};
606 $full_check = $wanted->{follow};
607 $follow = $full_check || $wanted->{follow_fast};
608 $follow_skip = $wanted->{follow_skip};
609 $untaint = $wanted->{untaint};
610 $untaint_pat = $wanted->{untaint_pattern};
611 $untaint_skip = $wanted->{untaint_skip};
612 $dangling_symlinks = $wanted->{dangling_symlinks};
81793b90 613
1cffc1dd 614 # for compatibility reasons (find.pl, find2perl)
9f826d6a 615 local our ($topdir, $topdev, $topino, $topmode, $topnlink);
81793b90
GS
616
617 # a symbolic link to a directory doesn't increase the link count
618 $avoid_nlink = $follow || $File::Find::dont_use_nlink;
3555aed3 619
e7b91b67 620 my ($abs_dir, $Is_Dir);
81793b90
GS
621
622 Proc_Top_Item:
4c621faf 623 foreach my $TOP (@_) {
7e47e6ff
JH
624 my $top_item = $TOP;
625
3555aed3
SP
626 ($topdev,$topino,$topmode,$topnlink) = $follow ? stat $top_item : lstat $top_item;
627
7e47e6ff 628 if ($Is_MacOS) {
7e47e6ff 629 $top_item = ":$top_item"
3fa6e24b 630 if ( (-d _) && ( $top_item !~ /:/ ) );
3555aed3
SP
631 } elsif ($^O eq 'MSWin32') {
632 $top_item =~ s|/\z|| unless $top_item =~ m|\w:/$|;
7e47e6ff
JH
633 }
634 else {
635 $top_item =~ s|/\z|| unless $top_item eq '/';
7e47e6ff
JH
636 }
637
638 $Is_Dir= 0;
639
640 if ($follow) {
641
642 if ($Is_MacOS) {
643 $cwd = "$cwd:" unless ($cwd =~ /:$/); # for safety
644
645 if ($top_item eq $File::Find::current_dir) {
646 $abs_dir = $cwd;
647 }
648 else {
649 $abs_dir = contract_name_Mac($cwd, $top_item);
650 unless (defined $abs_dir) {
cd68ec93 651 warnings::warnif "Can't determine absolute path for $top_item (No such file or directory)\n";
7e47e6ff
JH
652 next Proc_Top_Item;
653 }
654 }
655
656 }
657 else {
658 if (substr($top_item,0,1) eq '/') {
659 $abs_dir = $top_item;
660 }
661 elsif ($top_item eq $File::Find::current_dir) {
662 $abs_dir = $cwd;
663 }
664 else { # care about any ../
665 $abs_dir = contract_name("$cwd/",$top_item);
666 }
667 }
668 $abs_dir= Follow_SymLink($abs_dir);
669 unless (defined $abs_dir) {
80e52b73
JH
670 if ($dangling_symlinks) {
671 if (ref $dangling_symlinks eq 'CODE') {
672 $dangling_symlinks->($top_item, $cwd);
673 } else {
cd68ec93 674 warnings::warnif "$top_item is a dangling symbolic link\n";
80e52b73
JH
675 }
676 }
81793b90 677 next Proc_Top_Item;
7e47e6ff
JH
678 }
679
680 if (-d _) {
81793b90
GS
681 _find_dir_symlnk($wanted, $abs_dir, $top_item);
682 $Is_Dir= 1;
7e47e6ff
JH
683 }
684 }
81793b90 685 else { # no follow
7e47e6ff
JH
686 $topdir = $top_item;
687 unless (defined $topnlink) {
cd68ec93 688 warnings::warnif "Can't stat $top_item: $!\n";
7e47e6ff
JH
689 next Proc_Top_Item;
690 }
691 if (-d _) {
544ff7a7 692 $top_item =~ s/\.dir\z//i if $Is_VMS;
e7b91b67 693 _find_dir($wanted, $top_item, $topnlink);
81793b90 694 $Is_Dir= 1;
7e47e6ff 695 }
237437d0 696 else {
81793b90 697 $abs_dir= $top_item;
7e47e6ff
JH
698 }
699 }
81793b90 700
7e47e6ff 701 unless ($Is_Dir) {
81793b90 702 unless (($_,$dir) = File::Basename::fileparse($abs_dir)) {
7e47e6ff
JH
703 if ($Is_MacOS) {
704 ($dir,$_) = (':', $top_item); # $File::Find::dir, $_
705 }
706 else {
707 ($dir,$_) = ('./', $top_item);
708 }
81793b90
GS
709 }
710
7e47e6ff
JH
711 $abs_dir = $dir;
712 if (( $untaint ) && (is_tainted($dir) )) {
713 ( $abs_dir ) = $dir =~ m|$untaint_pat|;
81793b90
GS
714 unless (defined $abs_dir) {
715 if ($untaint_skip == 0) {
7e47e6ff 716 die "directory $dir is still tainted";
81793b90
GS
717 }
718 else {
719 next Proc_Top_Item;
720 }
721 }
7e47e6ff 722 }
81793b90 723
7e47e6ff 724 unless ($no_chdir || chdir $abs_dir) {
cd68ec93 725 warnings::warnif "Couldn't chdir $abs_dir: $!\n";
7e47e6ff
JH
726 next Proc_Top_Item;
727 }
719911cc 728
7e47e6ff 729 $name = $abs_dir . $_; # $File::Find::name
3bb6d3e5 730 $_ = $name if $no_chdir;
719911cc 731
abfdd623 732 { $wanted_callback->() }; # protect against wild "next"
81793b90 733
7e47e6ff 734 }
81793b90 735
7e47e6ff
JH
736 unless ( $no_chdir ) {
737 if ( ($check_t_cwd) && (($untaint) && (is_tainted($cwd) )) ) {
738 ( $cwd_untainted ) = $cwd =~ m|$untaint_pat|;
739 unless (defined $cwd_untainted) {
740 die "insecure cwd in find(depth)";
741 }
742 $check_t_cwd = 0;
743 }
744 unless (chdir $cwd_untainted) {
745 die "Can't cd to $cwd: $!\n";
746 }
747 }
81793b90
GS
748 }
749}
750
751# API:
752# $wanted
753# $p_dir : "parent directory"
754# $nlink : what came back from the stat
755# preconditions:
756# chdir (if not no_chdir) to dir
757
758sub _find_dir($$$) {
759 my ($wanted, $p_dir, $nlink) = @_;
760 my ($CdLvl,$Level) = (0,0);
761 my @Stack;
762 my @filenames;
763 my ($subcount,$sub_nlink);
764 my $SE= [];
765 my $dir_name= $p_dir;
7e47e6ff 766 my $dir_pref;
39e79f6b 767 my $dir_rel = $File::Find::current_dir;
7e47e6ff 768 my $tainted = 0;
5fa2bf2b 769 my $no_nlink;
7e47e6ff
JH
770
771 if ($Is_MacOS) {
772 $dir_pref= ($p_dir =~ /:$/) ? $p_dir : "$p_dir:"; # preface
3555aed3
SP
773 } elsif ($^O eq 'MSWin32') {
774 $dir_pref = ($p_dir =~ m|\w:/$| ? $p_dir : "$p_dir/" );
7e47e6ff
JH
775 }
776 else {
777 $dir_pref= ( $p_dir eq '/' ? '/' : "$p_dir/" );
7e47e6ff 778 }
81793b90
GS
779
780 local ($dir, $name, $prune, *DIR);
7e47e6ff
JH
781
782 unless ( $no_chdir || ($p_dir eq $File::Find::current_dir)) {
81793b90 783 my $udir = $p_dir;
7e47e6ff
JH
784 if (( $untaint ) && (is_tainted($p_dir) )) {
785 ( $udir ) = $p_dir =~ m|$untaint_pat|;
81793b90
GS
786 unless (defined $udir) {
787 if ($untaint_skip == 0) {
788 die "directory $p_dir is still tainted";
789 }
790 else {
791 return;
792 }
237437d0 793 }
a0d0e21e 794 }
8d8eebbf 795 unless (chdir ($Is_VMS && $udir !~ /[\/\[<]+/ ? "./$udir" : $udir)) {
cd68ec93 796 warnings::warnif "Can't cd to $udir: $!\n";
81793b90
GS
797 return;
798 }
799 }
7e47e6ff
JH
800
801 # push the starting directory
57e73c4b 802 push @Stack,[$CdLvl,$p_dir,$dir_rel,-1] if $bydepth;
81793b90 803
7e47e6ff
JH
804 if ($Is_MacOS) {
805 $p_dir = $dir_pref; # ensure trailing ':'
806 }
807
81793b90
GS
808 while (defined $SE) {
809 unless ($bydepth) {
3555aed3
SP
810 $dir= $p_dir; # $File::Find::dir
811 $name= $dir_name; # $File::Find::name
7e47e6ff 812 $_= ($no_chdir ? $dir_name : $dir_rel ); # $_
81793b90 813 # prune may happen here
7e47e6ff 814 $prune= 0;
abfdd623 815 { $wanted_callback->() }; # protect against wild "next"
7e47e6ff 816 next if $prune;
81793b90 817 }
7e47e6ff 818
81793b90 819 # change to that directory
7e47e6ff 820 unless ($no_chdir || ($dir_rel eq $File::Find::current_dir)) {
81793b90 821 my $udir= $dir_rel;
7e47e6ff
JH
822 if ( ($untaint) && (($tainted) || ($tainted = is_tainted($dir_rel) )) ) {
823 ( $udir ) = $dir_rel =~ m|$untaint_pat|;
81793b90
GS
824 unless (defined $udir) {
825 if ($untaint_skip == 0) {
7e47e6ff
JH
826 if ($Is_MacOS) {
827 die "directory ($p_dir) $dir_rel is still tainted";
828 }
829 else {
830 die "directory (" . ($p_dir ne '/' ? $p_dir : '') . "/) $dir_rel is still tainted";
831 }
832 } else { # $untaint_skip == 1
3555aed3 833 next;
81793b90
GS
834 }
835 }
836 }
8d8eebbf 837 unless (chdir ($Is_VMS && $udir !~ /[\/\[<]+/ ? "./$udir" : $udir)) {
7e47e6ff 838 if ($Is_MacOS) {
cd68ec93 839 warnings::warnif "Can't cd to ($p_dir) $udir: $!\n";
7e47e6ff
JH
840 }
841 else {
cd68ec93
RGS
842 warnings::warnif "Can't cd to (" .
843 ($p_dir ne '/' ? $p_dir : '') . "/) $udir: $!\n";
7e47e6ff 844 }
81793b90
GS
845 next;
846 }
847 $CdLvl++;
848 }
849
7e47e6ff
JH
850 if ($Is_MacOS) {
851 $dir_name = "$dir_name:" unless ($dir_name =~ /:$/);
852 }
853
3555aed3 854 $dir= $dir_name; # $File::Find::dir
81793b90
GS
855
856 # Get the list of files in the current directory.
7e47e6ff 857 unless (opendir DIR, ($no_chdir ? $dir_name : $File::Find::current_dir)) {
cd68ec93 858 warnings::warnif "Can't opendir($dir_name): $!\n";
81793b90
GS
859 next;
860 }
861 @filenames = readdir DIR;
862 closedir(DIR);
abfdd623 863 @filenames = $pre_process->(@filenames) if $pre_process;
719c805e 864 push @Stack,[$CdLvl,$dir_name,"",-2] if $post_process;
81793b90 865
5fa2bf2b
DD
866 # default: use whatever was specifid
867 # (if $nlink >= 2, and $avoid_nlink == 0, this will switch back)
868 $no_nlink = $avoid_nlink;
869 # if dir has wrong nlink count, force switch to slower stat method
870 $no_nlink = 1 if ($nlink < 2);
871
872 if ($nlink == 2 && !$no_nlink) {
81793b90
GS
873 # This dir has no subdirectories.
874 for my $FN (@filenames) {
7e47e6ff 875 next if $FN =~ $File::Find::skip_pattern;
81793b90 876
7e47e6ff
JH
877 $name = $dir_pref . $FN; # $File::Find::name
878 $_ = ($no_chdir ? $name : $FN); # $_
abfdd623 879 { $wanted_callback->() }; # protect against wild "next"
81793b90
GS
880 }
881
882 }
883 else {
884 # This dir has subdirectories.
885 $subcount = $nlink - 2;
886
7bd31527
JH
887 # HACK: insert directories at this position. so as to preserve
888 # the user pre-processed ordering of files.
889 # EG: directory traversal is in user sorted order, not at random.
890 my $stack_top = @Stack;
891
81793b90 892 for my $FN (@filenames) {
7e47e6ff 893 next if $FN =~ $File::Find::skip_pattern;
5fa2bf2b 894 if ($subcount > 0 || $no_nlink) {
81793b90
GS
895 # Seen all the subdirs?
896 # check for directoriness.
897 # stat is faster for a file in the current directory
07867069 898 $sub_nlink = (lstat ($no_chdir ? $dir_pref . $FN : $FN))[3];
81793b90
GS
899
900 if (-d _) {
901 --$subcount;
544ff7a7 902 $FN =~ s/\.dir\z//i if $Is_VMS;
7bd31527
JH
903 # HACK: replace push to preserve dir traversal order
904 #push @Stack,[$CdLvl,$dir_name,$FN,$sub_nlink];
905 splice @Stack, $stack_top, 0,
906 [$CdLvl,$dir_name,$FN,$sub_nlink];
81793b90
GS
907 }
908 else {
7e47e6ff
JH
909 $name = $dir_pref . $FN; # $File::Find::name
910 $_= ($no_chdir ? $name : $FN); # $_
abfdd623 911 { $wanted_callback->() }; # protect against wild "next"
81793b90
GS
912 }
913 }
07867069 914 else {
7e47e6ff
JH
915 $name = $dir_pref . $FN; # $File::Find::name
916 $_= ($no_chdir ? $name : $FN); # $_
abfdd623 917 { $wanted_callback->() }; # protect against wild "next"
81793b90
GS
918 }
919 }
920 }
17b275ff
RA
921 }
922 continue {
57e73c4b 923 while ( defined ($SE = pop @Stack) ) {
81793b90
GS
924 ($Level, $p_dir, $dir_rel, $nlink) = @$SE;
925 if ($CdLvl > $Level && !$no_chdir) {
7e47e6ff
JH
926 my $tmp;
927 if ($Is_MacOS) {
928 $tmp = (':' x ($CdLvl-$Level)) . ':';
929 }
930 else {
931 $tmp = join('/',('..') x ($CdLvl-$Level));
932 }
933 die "Can't cd to $dir_name" . $tmp
934 unless chdir ($tmp);
81793b90
GS
935 $CdLvl = $Level;
936 }
7e47e6ff
JH
937
938 if ($Is_MacOS) {
939 # $pdir always has a trailing ':', except for the starting dir,
940 # where $dir_rel eq ':'
941 $dir_name = "$p_dir$dir_rel";
942 $dir_pref = "$dir_name:";
943 }
3555aed3
SP
944 elsif ($^O eq 'MSWin32') {
945 $dir_name = ($p_dir =~ m|\w:/$| ? "$p_dir$dir_rel" : "$p_dir/$dir_rel");
946 $dir_pref = "$dir_name/";
947 }
7e47e6ff
JH
948 else {
949 $dir_name = ($p_dir eq '/' ? "/$dir_rel" : "$p_dir/$dir_rel");
950 $dir_pref = "$dir_name/";
951 }
952
719c805e 953 if ( $nlink == -2 ) {
7e47e6ff 954 $name = $dir = $p_dir; # $File::Find::name / dir
39e79f6b 955 $_ = $File::Find::current_dir;
abfdd623 956 $post_process->(); # End-of-directory processing
7e47e6ff
JH
957 }
958 elsif ( $nlink < 0 ) { # must be finddepth, report dirname now
959 $name = $dir_name;
960 if ($Is_MacOS) {
961 if ($dir_rel eq ':') { # must be the top dir, where we started
962 $name =~ s|:$||; # $File::Find::name
963 $p_dir = "$p_dir:" unless ($p_dir =~ /:$/);
964 }
965 $dir = $p_dir; # $File::Find::dir
966 $_ = ($no_chdir ? $name : $dir_rel); # $_
967 }
968 else {
969 if ( substr($name,-2) eq '/.' ) {
5cf0a2f2 970 substr($name, length($name) == 2 ? -1 : -2) = '';
7e47e6ff
JH
971 }
972 $dir = $p_dir;
973 $_ = ($no_chdir ? $dir_name : $dir_rel );
974 if ( substr($_,-2) eq '/.' ) {
5cf0a2f2 975 substr($_, length($_) == 2 ? -1 : -2) = '';
7e47e6ff
JH
976 }
977 }
abfdd623 978 { $wanted_callback->() }; # protect against wild "next"
7e47e6ff
JH
979 }
980 else {
981 push @Stack,[$CdLvl,$p_dir,$dir_rel,-1] if $bydepth;
982 last;
983 }
81793b90 984 }
a0d0e21e
LW
985 }
986}
987
81793b90
GS
988
989# API:
990# $wanted
991# $dir_loc : absolute location of a dir
992# $p_dir : "parent directory"
993# preconditions:
994# chdir (if not no_chdir) to dir
995
996sub _find_dir_symlnk($$$) {
7e47e6ff 997 my ($wanted, $dir_loc, $p_dir) = @_; # $dir_loc is the absolute directory
81793b90
GS
998 my @Stack;
999 my @filenames;
1000 my $new_loc;
7e47e6ff 1001 my $updir_loc = $dir_loc; # untainted parent directory
81793b90
GS
1002 my $SE = [];
1003 my $dir_name = $p_dir;
7e47e6ff
JH
1004 my $dir_pref;
1005 my $loc_pref;
39e79f6b 1006 my $dir_rel = $File::Find::current_dir;
7e47e6ff
JH
1007 my $byd_flag; # flag for pending stack entry if $bydepth
1008 my $tainted = 0;
1009 my $ok = 1;
1010
1011 if ($Is_MacOS) {
1012 $dir_pref = ($p_dir =~ /:$/) ? "$p_dir" : "$p_dir:";
1013 $loc_pref = ($dir_loc =~ /:$/) ? "$dir_loc" : "$dir_loc:";
7e47e6ff
JH
1014 } else {
1015 $dir_pref = ( $p_dir eq '/' ? '/' : "$p_dir/" );
1016 $loc_pref = ( $dir_loc eq '/' ? '/' : "$dir_loc/" );
7e47e6ff 1017 }
81793b90
GS
1018
1019 local ($dir, $name, $fullname, $prune, *DIR);
7e47e6ff
JH
1020
1021 unless ($no_chdir) {
1022 # untaint the topdir
1023 if (( $untaint ) && (is_tainted($dir_loc) )) {
1024 ( $updir_loc ) = $dir_loc =~ m|$untaint_pat|; # parent dir, now untainted
1025 # once untainted, $updir_loc is pushed on the stack (as parent directory);
3555aed3
SP
1026 # hence, we don't need to untaint the parent directory every time we chdir
1027 # to it later
7e47e6ff 1028 unless (defined $updir_loc) {
81793b90
GS
1029 if ($untaint_skip == 0) {
1030 die "directory $dir_loc is still tainted";
1031 }
1032 else {
1033 return;
1034 }
1035 }
1036 }
7e47e6ff
JH
1037 $ok = chdir($updir_loc) unless ($p_dir eq $File::Find::current_dir);
1038 unless ($ok) {
cd68ec93 1039 warnings::warnif "Can't cd to $updir_loc: $!\n";
81793b90
GS
1040 return;
1041 }
1042 }
1043
7e47e6ff
JH
1044 push @Stack,[$dir_loc,$updir_loc,$p_dir,$dir_rel,-1] if $bydepth;
1045
1046 if ($Is_MacOS) {
1047 $p_dir = $dir_pref; # ensure trailing ':'
1048 }
57e73c4b 1049
81793b90
GS
1050 while (defined $SE) {
1051
1052 unless ($bydepth) {
7e47e6ff 1053 # change (back) to parent directory (always untainted)
704ea872 1054 unless ($no_chdir) {
7e47e6ff 1055 unless (chdir $updir_loc) {
cd68ec93 1056 warnings::warnif "Can't cd to $updir_loc: $!\n";
704ea872
GS
1057 next;
1058 }
1059 }
7e47e6ff
JH
1060 $dir= $p_dir; # $File::Find::dir
1061 $name= $dir_name; # $File::Find::name
1062 $_= ($no_chdir ? $dir_name : $dir_rel ); # $_
1063 $fullname= $dir_loc; # $File::Find::fullname
81793b90 1064 # prune may happen here
7e47e6ff 1065 $prune= 0;
704ea872 1066 lstat($_); # make sure file tests with '_' work
abfdd623 1067 { $wanted_callback->() }; # protect against wild "next"
7e47e6ff 1068 next if $prune;
81793b90
GS
1069 }
1070
1071 # change to that directory
7e47e6ff
JH
1072 unless ($no_chdir || ($dir_rel eq $File::Find::current_dir)) {
1073 $updir_loc = $dir_loc;
1074 if ( ($untaint) && (($tainted) || ($tainted = is_tainted($dir_loc) )) ) {
3555aed3 1075 # untaint $dir_loc, what will be pushed on the stack as (untainted) parent dir
7e47e6ff
JH
1076 ( $updir_loc ) = $dir_loc =~ m|$untaint_pat|;
1077 unless (defined $updir_loc) {
81793b90
GS
1078 if ($untaint_skip == 0) {
1079 die "directory $dir_loc is still tainted";
a0d0e21e 1080 }
237437d0 1081 else {
81793b90 1082 next;
237437d0 1083 }
a0d0e21e
LW
1084 }
1085 }
7e47e6ff 1086 unless (chdir $updir_loc) {
cd68ec93 1087 warnings::warnif "Can't cd to $updir_loc: $!\n";
81793b90
GS
1088 next;
1089 }
1090 }
1091
7e47e6ff
JH
1092 if ($Is_MacOS) {
1093 $dir_name = "$dir_name:" unless ($dir_name =~ /:$/);
1094 }
1095
1096 $dir = $dir_name; # $File::Find::dir
81793b90
GS
1097
1098 # Get the list of files in the current directory.
7e47e6ff 1099 unless (opendir DIR, ($no_chdir ? $dir_loc : $File::Find::current_dir)) {
cd68ec93 1100 warnings::warnif "Can't opendir($dir_loc): $!\n";
81793b90
GS
1101 next;
1102 }
1103 @filenames = readdir DIR;
1104 closedir(DIR);
1105
1106 for my $FN (@filenames) {
7e47e6ff 1107 next if $FN =~ $File::Find::skip_pattern;
81793b90
GS
1108
1109 # follow symbolic links / do an lstat
07867069 1110 $new_loc = Follow_SymLink($loc_pref.$FN);
81793b90
GS
1111
1112 # ignore if invalid symlink
3555aed3 1113 unless (defined $new_loc) {
615a2b9b
SP
1114 if ($dangling_symlinks) {
1115 if (ref $dangling_symlinks eq 'CODE') {
1116 $dangling_symlinks->($FN, $dir_pref);
1117 } else {
1118 warnings::warnif "$dir_pref$FN is a dangling symbolic link\n";
1119 }
1120 }
1121
1122 $fullname = undef;
1123 $name = $dir_pref . $FN;
1124 $_ = ($no_chdir ? $name : $FN);
1125 { $wanted_callback->() };
1126 next;
1127 }
7e47e6ff 1128
81793b90 1129 if (-d _) {
7e47e6ff 1130 push @Stack,[$new_loc,$updir_loc,$dir_name,$FN,1];
81793b90
GS
1131 }
1132 else {
3555aed3 1133 $fullname = $new_loc; # $File::Find::fullname
7e47e6ff
JH
1134 $name = $dir_pref . $FN; # $File::Find::name
1135 $_ = ($no_chdir ? $name : $FN); # $_
abfdd623 1136 { $wanted_callback->() }; # protect against wild "next"
81793b90
GS
1137 }
1138 }
1139
81793b90
GS
1140 }
1141 continue {
57e73c4b 1142 while (defined($SE = pop @Stack)) {
7e47e6ff
JH
1143 ($dir_loc, $updir_loc, $p_dir, $dir_rel, $byd_flag) = @$SE;
1144 if ($Is_MacOS) {
1145 # $p_dir always has a trailing ':', except for the starting dir,
1146 # where $dir_rel eq ':'
1147 $dir_name = "$p_dir$dir_rel";
1148 $dir_pref = "$dir_name:";
1149 $loc_pref = ($dir_loc =~ /:$/) ? $dir_loc : "$dir_loc:";
1150 }
1151 else {
1152 $dir_name = ($p_dir eq '/' ? "/$dir_rel" : "$p_dir/$dir_rel");
1153 $dir_pref = "$dir_name/";
1154 $loc_pref = "$dir_loc/";
1155 }
1156 if ( $byd_flag < 0 ) { # must be finddepth, report dirname now
1157 unless ($no_chdir || ($dir_rel eq $File::Find::current_dir)) {
3555aed3 1158 unless (chdir $updir_loc) { # $updir_loc (parent dir) is always untainted
cd68ec93 1159 warnings::warnif "Can't cd to $updir_loc: $!\n";
7e47e6ff
JH
1160 next;
1161 }
1162 }
1163 $fullname = $dir_loc; # $File::Find::fullname
1164 $name = $dir_name; # $File::Find::name
1165 if ($Is_MacOS) {
1166 if ($dir_rel eq ':') { # must be the top dir, where we started
1167 $name =~ s|:$||; # $File::Find::name
1168 $p_dir = "$p_dir:" unless ($p_dir =~ /:$/);
1169 }
1170 $dir = $p_dir; # $File::Find::dir
1171 $_ = ($no_chdir ? $name : $dir_rel); # $_
1172 }
1173 else {
1174 if ( substr($name,-2) eq '/.' ) {
f801979b 1175 substr($name, length($name) == 2 ? -1 : -2) = ''; # $File::Find::name
7e47e6ff
JH
1176 }
1177 $dir = $p_dir; # $File::Find::dir
1178 $_ = ($no_chdir ? $dir_name : $dir_rel); # $_
1179 if ( substr($_,-2) eq '/.' ) {
f801979b 1180 substr($_, length($_) == 2 ? -1 : -2) = '';
7e47e6ff
JH
1181 }
1182 }
1183
1184 lstat($_); # make sure file tests with '_' work
abfdd623 1185 { $wanted_callback->() }; # protect against wild "next"
7e47e6ff
JH
1186 }
1187 else {
1188 push @Stack,[$dir_loc, $updir_loc, $p_dir, $dir_rel,-1] if $bydepth;
1189 last;
1190 }
a0d0e21e
LW
1191 }
1192 }
1193}
1194
81793b90 1195
20408e3c 1196sub wrap_wanted {
81793b90
GS
1197 my $wanted = shift;
1198 if ( ref($wanted) eq 'HASH' ) {
1199 if ( $wanted->{follow} || $wanted->{follow_fast}) {
1200 $wanted->{follow_skip} = 1 unless defined $wanted->{follow_skip};
1201 }
1202 if ( $wanted->{untaint} ) {
3555aed3 1203 $wanted->{untaint_pattern} = $File::Find::untaint_pattern
81793b90
GS
1204 unless defined $wanted->{untaint_pattern};
1205 $wanted->{untaint_skip} = 0 unless defined $wanted->{untaint_skip};
1206 }
1207 return $wanted;
1208 }
1209 else {
1210 return { wanted => $wanted };
1211 }
a0d0e21e
LW
1212}
1213
20408e3c 1214sub find {
81793b90
GS
1215 my $wanted = shift;
1216 _find_opt(wrap_wanted($wanted), @_);
a0d0e21e
LW
1217}
1218
55d729e4 1219sub finddepth {
81793b90
GS
1220 my $wanted = wrap_wanted(shift);
1221 $wanted->{bydepth} = 1;
1222 _find_opt($wanted, @_);
20408e3c 1223}
6280b799 1224
7e47e6ff
JH
1225# default
1226$File::Find::skip_pattern = qr/^\.{1,2}\z/;
1227$File::Find::untaint_pattern = qr|^([-+@\w./]+)$|;
1228
6280b799 1229# These are hard-coded for now, but may move to hint files.
10eba763 1230if ($^O eq 'VMS') {
81793b90 1231 $Is_VMS = 1;
7e47e6ff
JH
1232 $File::Find::dont_use_nlink = 1;
1233}
1234elsif ($^O eq 'MacOS') {
1235 $Is_MacOS = 1;
1236 $File::Find::dont_use_nlink = 1;
1237 $File::Find::skip_pattern = qr/^Icon\015\z/;
1238 $File::Find::untaint_pattern = qr|^(.+)$|;
748a9306
LW
1239}
1240
7e47e6ff
JH
1241# this _should_ work properly on all platforms
1242# where File::Find can be expected to work
1243$File::Find::current_dir = File::Spec->curdir || '.';
1244
81793b90 1245$File::Find::dont_use_nlink = 1
497711e7 1246 if $^O eq 'os2' || $^O eq 'dos' || $^O eq 'amigaos' || $^O eq 'MSWin32' ||
0c52c6a9 1247 $^O eq 'interix' || $^O eq 'cygwin' || $^O eq 'epoc' || $^O eq 'qnx' ||
1119cb72 1248 $^O eq 'nto';
6280b799 1249
20408e3c
GS
1250# Set dont_use_nlink in your hint file if your system's stat doesn't
1251# report the number of links in a directory as an indication
1252# of the number of files.
1253# See, e.g. hints/machten.sh for MachTen 2.2.
81793b90
GS
1254unless ($File::Find::dont_use_nlink) {
1255 require Config;
1256 $File::Find::dont_use_nlink = 1 if ($Config::Config{'dont_use_nlink'});
20408e3c
GS
1257}
1258
3555aed3
SP
1259# We need a function that checks if a scalar is tainted. Either use the
1260# Scalar::Util module's tainted() function or our (slower) pure Perl
7e47e6ff
JH
1261# fallback is_tainted_pp()
1262{
1263 local $@;
1264 eval { require Scalar::Util };
1265 *is_tainted = $@ ? \&is_tainted_pp : \&Scalar::Util::tainted;
1266}
1267
a0d0e21e 12681;