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