Upgrade to Compress::Zlib 1.40
[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
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 127
128There is a variable C<$File::Find::fullname> which holds the absolute
615a2b9b 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 131
132=back
133
134=item C<follow_fast>
135
f10e1564 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 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 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 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 163=item C<no_chdir>
164
95e23d19 165Does not C<chdir()> to each directory as it recurses. The C<wanted()>
81793b90 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 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 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 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 188
189=back
190
abfdd623 191=head2 The wanted function
192
95e23d19 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 200through a collection of variables.
201
202=over 4
203
f837ebe2 204=item C<$File::Find::dir> is the current directory name,
abfdd623 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 209
210=back
211
f837ebe2 212Don't modify these variables.
213
95e23d19 214For example, when examining the file F</some/path/foo.ext> you will have:
abfdd623 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 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 226
227 $File::Find::name $File::Find::dir $_
228 default / / .
229 no_chdir=>0 /etc / etc
230 /etc/x /etc x
abfdd623 231
5cf0a2f2 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 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 247
248 find2perl / -name .nfs\* -mtime +7 \
81793b90 249 -exec rm -f {} \; -o -fstype nfs -prune
f06db76b 250
251produces something like:
252
253 sub wanted {
c7b9dd21 254 /^\.nfs.*\z/s &&
81793b90 255 (($dev, $ino, $mode, $nlink, $uid, $gid) = lstat($_)) &&
f06db76b 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 262 }
263
43dece2a 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 268Here's another interesting wanted function. It will find all symbolic
269links that don't resolve:
f06db76b 270
271 sub wanted {
81793b90 272 -l && !-e && print "bogus link: $File::Find::name\n";
237437d0 273 }
f06db76b 274
81793b90 275See also the script C<pfind> on CPAN for a nice application of this
276module.
277
cd68ec93 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 289=head1 CAVEAT
290
5fa2bf2b 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 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 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 306
307=item symlinks
308
f10e1564 309Be aware that the option to follow symbolic links can be dangerous.
81793b90 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 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 317=back
318
7e47e6ff 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 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 335trailing ':' is required.
336
3555aed3 337=item *
7e47e6ff 338
3555aed3 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 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 349C<qr|^(.+)$|>. Note that the parentheses are vital.
350
3555aed3 351=item *
7e47e6ff 352
3555aed3 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 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 367 my ($fileCat, $fileInfo);
368 my $invisible_flag = 1 << 14;
7e47e6ff 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 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 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 388volume actually maintains its own "Desktop Folder" directory.
389
390=back
391
392=back
0530a6c4 393
6eb87ff8 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 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 406=cut
407
b75c8c73 408our @ISA = qw(Exporter);
409our @EXPORT = qw(find finddepth);
6280b799 410
a0d0e21e 411
81793b90 412use strict;
413my $Is_VMS;
7e47e6ff 414my $Is_MacOS;
81793b90 415
416require File::Basename;
7e47e6ff 417require File::Spec;
81793b90 418
9f826d6a 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 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 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 440 }
441
442 return $abs_name;
443}
444
7e47e6ff 445# return the absolute name of a directory or file
446sub contract_name_Mac {
3555aed3 447 my ($cdir,$fn) = @_;
7e47e6ff 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 457 else {
458 # need to move up the tree, but
7e47e6ff 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 487 return undef;
488 }
489 }
490}
81793b90 491
492sub PathCombine($$) {
493 my ($Base,$Name) = @_;
494 my $AbsName;
495
7e47e6ff 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 500
501 # (simple) check for recursion
502 if ( ( $Base =~ /^$AbsName/) && (-d $AbsName) ) { # recursion
503 return undef;
504 }
81793b90 505 }
506 else {
7e47e6ff 507 if (substr($Name,0,1) eq '/') {
508 $AbsName= $Name;
509 }
510 else {
511 $AbsName= contract_name($Base,$Name);
512 }
81793b90 513
7e47e6ff 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 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 537 }
538 else {
81793b90 539 return undef;
a0d0e21e 540 }
541 }
81793b90 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 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 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 571sub _find_dir_symlnk($$$);
572sub _find_dir($$$);
573
7e47e6ff 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 584sub _find_opt {
585 my $wanted = shift;
586 die "invalid top directory" unless defined $_[0];
587
9f826d6a 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 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 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 621
622 Proc_Top_Item:
4c621faf 623 foreach my $TOP (@_) {
7e47e6ff 624 my $top_item = $TOP;
625
3555aed3 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 631 } elsif ($^O eq 'MSWin32') {
632 $top_item =~ s|/\z|| unless $top_item =~ m|\w:/$|;
7e47e6ff 633 }
634 else {
635 $top_item =~ s|/\z|| unless $top_item eq '/';
7e47e6ff 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 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 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 675 }
676 }
81793b90 677 next Proc_Top_Item;
7e47e6ff 678 }
679
680 if (-d _) {
81793b90 681 _find_dir_symlnk($wanted, $abs_dir, $top_item);
682 $Is_Dir= 1;
7e47e6ff 683 }
684 }
81793b90 685 else { # no follow
7e47e6ff 686 $topdir = $top_item;
687 unless (defined $topnlink) {
cd68ec93 688 warnings::warnif "Can't stat $top_item: $!\n";
7e47e6ff 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 698 }
699 }
81793b90 700
7e47e6ff 701 unless ($Is_Dir) {
81793b90 702 unless (($_,$dir) = File::Basename::fileparse($abs_dir)) {
7e47e6ff 703 if ($Is_MacOS) {
704 ($dir,$_) = (':', $top_item); # $File::Find::dir, $_
705 }
706 else {
707 ($dir,$_) = ('./', $top_item);
708 }
81793b90 709 }
710
7e47e6ff 711 $abs_dir = $dir;
712 if (( $untaint ) && (is_tainted($dir) )) {
713 ( $abs_dir ) = $dir =~ m|$untaint_pat|;
81793b90 714 unless (defined $abs_dir) {
715 if ($untaint_skip == 0) {
7e47e6ff 716 die "directory $dir is still tainted";
81793b90 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 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 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 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 770
771 if ($Is_MacOS) {
772 $dir_pref= ($p_dir =~ /:$/) ? $p_dir : "$p_dir:"; # preface
3555aed3 773 } elsif ($^O eq 'MSWin32') {
774 $dir_pref = ($p_dir =~ m|\w:/$| ? $p_dir : "$p_dir/" );
7e47e6ff 775 }
776 else {
777 $dir_pref= ( $p_dir eq '/' ? '/' : "$p_dir/" );
7e47e6ff 778 }
81793b90 779
780 local ($dir, $name, $prune, *DIR);
7e47e6ff 781
782 unless ( $no_chdir || ($p_dir eq $File::Find::current_dir)) {
81793b90 783 my $udir = $p_dir;
7e47e6ff 784 if (( $untaint ) && (is_tainted($p_dir) )) {
785 ( $udir ) = $p_dir =~ m|$untaint_pat|;
81793b90 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 797 return;
798 }
799 }
7e47e6ff 800
801 # push the starting directory
57e73c4b 802 push @Stack,[$CdLvl,$p_dir,$dir_rel,-1] if $bydepth;
81793b90 803
7e47e6ff 804 if ($Is_MacOS) {
805 $p_dir = $dir_pref; # ensure trailing ':'
806 }
807
81793b90 808 while (defined $SE) {
809 unless ($bydepth) {
3555aed3 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 822 if ( ($untaint) && (($tainted) || ($tainted = is_tainted($dir_rel) )) ) {
823 ( $udir ) = $dir_rel =~ m|$untaint_pat|;
81793b90 824 unless (defined $udir) {
825 if ($untaint_skip == 0) {
7e47e6ff 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 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 840 }
841 else {
cd68ec93 842 warnings::warnif "Can't cd to (" .
843 ($p_dir ne '/' ? $p_dir : '') . "/) $udir: $!\n";
7e47e6ff 844 }
81793b90 845 next;
846 }
847 $CdLvl++;
848 }
849
7e47e6ff 850 if ($Is_MacOS) {
851 $dir_name = "$dir_name:" unless ($dir_name =~ /:$/);
852 }
853
3555aed3 854 $dir= $dir_name; # $File::Find::dir
81793b90 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 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 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 873 # This dir has no subdirectories.
874 for my $FN (@filenames) {
7e47e6ff 875 next if $FN =~ $File::Find::skip_pattern;
81793b90 876
7e47e6ff 877 $name = $dir_pref . $FN; # $File::Find::name
878 $_ = ($no_chdir ? $name : $FN); # $_
abfdd623 879 { $wanted_callback->() }; # protect against wild "next"
81793b90 880 }
881
882 }
883 else {
884 # This dir has subdirectories.
885 $subcount = $nlink - 2;
886
7bd31527 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 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 899
900 if (-d _) {
901 --$subcount;
544ff7a7 902 $FN =~ s/\.dir\z//i if $Is_VMS;
7bd31527 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 907 }
908 else {
7e47e6ff 909 $name = $dir_pref . $FN; # $File::Find::name
910 $_= ($no_chdir ? $name : $FN); # $_
abfdd623 911 { $wanted_callback->() }; # protect against wild "next"
81793b90 912 }
913 }
07867069 914 else {
7e47e6ff 915 $name = $dir_pref . $FN; # $File::Find::name
916 $_= ($no_chdir ? $name : $FN); # $_
abfdd623 917 { $wanted_callback->() }; # protect against wild "next"
81793b90 918 }
919 }
920 }
17b275ff 921 }
922 continue {
57e73c4b 923 while ( defined ($SE = pop @Stack) ) {
81793b90 924 ($Level, $p_dir, $dir_rel, $nlink) = @$SE;
925 if ($CdLvl > $Level && !$no_chdir) {
7e47e6ff 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 935 $CdLvl = $Level;
936 }
7e47e6ff 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 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 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 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 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 976 }
977 }
abfdd623 978 { $wanted_callback->() }; # protect against wild "next"
7e47e6ff 979 }
980 else {
981 push @Stack,[$CdLvl,$p_dir,$dir_rel,-1] if $bydepth;
982 last;
983 }
81793b90 984 }
a0d0e21e 985 }
986}
987
81793b90 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 998 my @Stack;
999 my @filenames;
1000 my $new_loc;
7e47e6ff 1001 my $updir_loc = $dir_loc; # untainted parent directory
81793b90 1002 my $SE = [];
1003 my $dir_name = $p_dir;
7e47e6ff 1004 my $dir_pref;
1005 my $loc_pref;
39e79f6b 1006 my $dir_rel = $File::Find::current_dir;
7e47e6ff 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 1014 } else {
1015 $dir_pref = ( $p_dir eq '/' ? '/' : "$p_dir/" );
1016 $loc_pref = ( $dir_loc eq '/' ? '/' : "$dir_loc/" );
7e47e6ff 1017 }
81793b90 1018
1019 local ($dir, $name, $fullname, $prune, *DIR);
7e47e6ff 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 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 1029 if ($untaint_skip == 0) {
1030 die "directory $dir_loc is still tainted";
1031 }
1032 else {
1033 return;
1034 }
1035 }
1036 }
7e47e6ff 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 1040 return;
1041 }
1042 }
1043
7e47e6ff 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 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 1057 next;
1058 }
1059 }
7e47e6ff 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 1069 }
1070
1071 # change to that directory
7e47e6ff 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 1076 ( $updir_loc ) = $dir_loc =~ m|$untaint_pat|;
1077 unless (defined $updir_loc) {
81793b90 1078 if ($untaint_skip == 0) {
1079 die "directory $dir_loc is still tainted";
a0d0e21e 1080 }
237437d0 1081 else {
81793b90 1082 next;
237437d0 1083 }
a0d0e21e 1084 }
1085 }
7e47e6ff 1086 unless (chdir $updir_loc) {
cd68ec93 1087 warnings::warnif "Can't cd to $updir_loc: $!\n";
81793b90 1088 next;
1089 }
1090 }
1091
7e47e6ff 1092 if ($Is_MacOS) {
1093 $dir_name = "$dir_name:" unless ($dir_name =~ /:$/);
1094 }
1095
1096 $dir = $dir_name; # $File::Find::dir
81793b90 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 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 1108
1109 # follow symbolic links / do an lstat
07867069 1110 $new_loc = Follow_SymLink($loc_pref.$FN);
81793b90 1111
1112 # ignore if invalid symlink
3555aed3 1113 unless (defined $new_loc) {
615a2b9b 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 1131 }
1132 else {
3555aed3 1133 $fullname = $new_loc; # $File::Find::fullname
7e47e6ff 1134 $name = $dir_pref . $FN; # $File::Find::name
1135 $_ = ($no_chdir ? $name : $FN); # $_
abfdd623 1136 { $wanted_callback->() }; # protect against wild "next"
81793b90 1137 }
1138 }
1139
81793b90 1140 }
1141 continue {
57e73c4b 1142 while (defined($SE = pop @Stack)) {
7e47e6ff 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 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 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 1181 }
1182 }
1183
1184 lstat($_); # make sure file tests with '_' work
abfdd623 1185 { $wanted_callback->() }; # protect against wild "next"
7e47e6ff 1186 }
1187 else {
1188 push @Stack,[$dir_loc, $updir_loc, $p_dir, $dir_rel,-1] if $bydepth;
1189 last;
1190 }
a0d0e21e 1191 }
1192 }
1193}
1194
81793b90 1195
20408e3c 1196sub wrap_wanted {
81793b90 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 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 1212}
1213
20408e3c 1214sub find {
81793b90 1215 my $wanted = shift;
1216 _find_opt(wrap_wanted($wanted), @_);
a0d0e21e 1217}
1218
55d729e4 1219sub finddepth {
81793b90 1220 my $wanted = wrap_wanted(shift);
1221 $wanted->{bydepth} = 1;
1222 _find_opt($wanted, @_);
20408e3c 1223}
6280b799 1224
7e47e6ff 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 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 1239}
1240
7e47e6ff 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 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 1254unless ($File::Find::dont_use_nlink) {
1255 require Config;
1256 $File::Find::dont_use_nlink = 1 if ($Config::Config{'dont_use_nlink'});
20408e3c 1257}
1258
3555aed3 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 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;