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