Upgrade to PathTools 3.09
[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;
0c52c6a9 6our $VERSION = '1.09';
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
7e47e6ff 91The value should be a code reference. This code reference is used to
95e23d19 92preprocess the current directory. The name of the currently processed
93directory is in C<$File::Find::dir>. Your preprocessing function is
94called after C<readdir()>, but before the loop that calls the C<wanted()>
7e47e6ff 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
99I<follow> or I<follow_fast> are in effect, C<preprocess> is a no-op.
719c805e 100
101=item C<postprocess>
102
7e47e6ff 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
95e23d19 105arguments. The name of the current directory is in C<$File::Find::dir>. This
7e47e6ff 106hook is handy for summarizing a directory, such as calculating its disk
3fa6e24b 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
146to be processed a second time. If a directory or a symbolic link
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
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
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.
181The default is set to C<qr|^([-+@\w./]+)$|>.
1cffc1dd 182Note that the parentheses are vital.
81793b90 183
184=item C<untaint_skip>
185
7e47e6ff 186If set, a directory which fails the I<untaint_pattern> is skipped,
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
220You are chdir()'d toC<$File::Find::dir> when the function is called,
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
312more than once (only if C<follow_fast> is in effect).
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
329=item *
330
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
335trailing ':' is required.
336
337=item *
338
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
343the absolute pathname of that directory with all symbolic links resolved,
344may or may not end with a ':'.
345
346=item *
347
348The default C<untaint_pattern> (see above) on Mac OS is set to
349C<qr|^(.+)$|>. Note that the parentheses are vital.
350
351=item *
352
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
358directories (requires Mac::Files):
359
360 use Mac::Files;
361
362 # invisible() -- returns 1 if file/directory is invisible,
1cffc1dd 363 # 0 if it's visible or undef if an error occurred
7e47e6ff 364
365 sub invisible($) {
366 my $file = shift;
367 my ($fileCat, $fileInfo);
368 my $invisible_flag = 1 << 14;
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
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
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
387all desktop files appear to be on the same "virtual" desktop, each disk
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 {
447 my ($cdir,$fn) = @_;
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 }
457 else {
458 # need to move up the tree, but
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 }
486 else { # argh!, $fn is not a valid directory/file
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()
499 $AbsName = $Name;
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;
582}
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;
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
626 if ($Is_MacOS) {
627 ($topdev,$topino,$topmode,$topnlink) = $follow ? stat $top_item : lstat $top_item;
628 $top_item = ":$top_item"
3fa6e24b 629 if ( (-d _) && ( $top_item !~ /:/ ) );
7e47e6ff 630 }
631 else {
632 $top_item =~ s|/\z|| unless $top_item eq '/';
633 ($topdev,$topino,$topmode,$topnlink) = $follow ? stat $top_item : lstat $top_item;
634 }
635
636 $Is_Dir= 0;
637
638 if ($follow) {
639
640 if ($Is_MacOS) {
641 $cwd = "$cwd:" unless ($cwd =~ /:$/); # for safety
642
643 if ($top_item eq $File::Find::current_dir) {
644 $abs_dir = $cwd;
645 }
646 else {
647 $abs_dir = contract_name_Mac($cwd, $top_item);
648 unless (defined $abs_dir) {
cd68ec93 649 warnings::warnif "Can't determine absolute path for $top_item (No such file or directory)\n";
7e47e6ff 650 next Proc_Top_Item;
651 }
652 }
653
654 }
655 else {
656 if (substr($top_item,0,1) eq '/') {
657 $abs_dir = $top_item;
658 }
659 elsif ($top_item eq $File::Find::current_dir) {
660 $abs_dir = $cwd;
661 }
662 else { # care about any ../
663 $abs_dir = contract_name("$cwd/",$top_item);
664 }
665 }
666 $abs_dir= Follow_SymLink($abs_dir);
667 unless (defined $abs_dir) {
80e52b73 668 if ($dangling_symlinks) {
669 if (ref $dangling_symlinks eq 'CODE') {
670 $dangling_symlinks->($top_item, $cwd);
671 } else {
cd68ec93 672 warnings::warnif "$top_item is a dangling symbolic link\n";
80e52b73 673 }
674 }
81793b90 675 next Proc_Top_Item;
7e47e6ff 676 }
677
678 if (-d _) {
81793b90 679 _find_dir_symlnk($wanted, $abs_dir, $top_item);
680 $Is_Dir= 1;
7e47e6ff 681 }
682 }
81793b90 683 else { # no follow
7e47e6ff 684 $topdir = $top_item;
685 unless (defined $topnlink) {
cd68ec93 686 warnings::warnif "Can't stat $top_item: $!\n";
7e47e6ff 687 next Proc_Top_Item;
688 }
689 if (-d _) {
544ff7a7 690 $top_item =~ s/\.dir\z//i if $Is_VMS;
e7b91b67 691 _find_dir($wanted, $top_item, $topnlink);
81793b90 692 $Is_Dir= 1;
7e47e6ff 693 }
237437d0 694 else {
81793b90 695 $abs_dir= $top_item;
7e47e6ff 696 }
697 }
81793b90 698
7e47e6ff 699 unless ($Is_Dir) {
81793b90 700 unless (($_,$dir) = File::Basename::fileparse($abs_dir)) {
7e47e6ff 701 if ($Is_MacOS) {
702 ($dir,$_) = (':', $top_item); # $File::Find::dir, $_
703 }
704 else {
705 ($dir,$_) = ('./', $top_item);
706 }
81793b90 707 }
708
7e47e6ff 709 $abs_dir = $dir;
710 if (( $untaint ) && (is_tainted($dir) )) {
711 ( $abs_dir ) = $dir =~ m|$untaint_pat|;
81793b90 712 unless (defined $abs_dir) {
713 if ($untaint_skip == 0) {
7e47e6ff 714 die "directory $dir is still tainted";
81793b90 715 }
716 else {
717 next Proc_Top_Item;
718 }
719 }
7e47e6ff 720 }
81793b90 721
7e47e6ff 722 unless ($no_chdir || chdir $abs_dir) {
cd68ec93 723 warnings::warnif "Couldn't chdir $abs_dir: $!\n";
7e47e6ff 724 next Proc_Top_Item;
725 }
719911cc 726
7e47e6ff 727 $name = $abs_dir . $_; # $File::Find::name
3bb6d3e5 728 $_ = $name if $no_chdir;
719911cc 729
abfdd623 730 { $wanted_callback->() }; # protect against wild "next"
81793b90 731
7e47e6ff 732 }
81793b90 733
7e47e6ff 734 unless ( $no_chdir ) {
735 if ( ($check_t_cwd) && (($untaint) && (is_tainted($cwd) )) ) {
736 ( $cwd_untainted ) = $cwd =~ m|$untaint_pat|;
737 unless (defined $cwd_untainted) {
738 die "insecure cwd in find(depth)";
739 }
740 $check_t_cwd = 0;
741 }
742 unless (chdir $cwd_untainted) {
743 die "Can't cd to $cwd: $!\n";
744 }
745 }
81793b90 746 }
747}
748
749# API:
750# $wanted
751# $p_dir : "parent directory"
752# $nlink : what came back from the stat
753# preconditions:
754# chdir (if not no_chdir) to dir
755
756sub _find_dir($$$) {
757 my ($wanted, $p_dir, $nlink) = @_;
758 my ($CdLvl,$Level) = (0,0);
759 my @Stack;
760 my @filenames;
761 my ($subcount,$sub_nlink);
762 my $SE= [];
763 my $dir_name= $p_dir;
7e47e6ff 764 my $dir_pref;
39e79f6b 765 my $dir_rel = $File::Find::current_dir;
7e47e6ff 766 my $tainted = 0;
5fa2bf2b 767 my $no_nlink;
7e47e6ff 768
769 if ($Is_MacOS) {
770 $dir_pref= ($p_dir =~ /:$/) ? $p_dir : "$p_dir:"; # preface
7e47e6ff 771 }
772 else {
773 $dir_pref= ( $p_dir eq '/' ? '/' : "$p_dir/" );
7e47e6ff 774 }
81793b90 775
776 local ($dir, $name, $prune, *DIR);
7e47e6ff 777
778 unless ( $no_chdir || ($p_dir eq $File::Find::current_dir)) {
81793b90 779 my $udir = $p_dir;
7e47e6ff 780 if (( $untaint ) && (is_tainted($p_dir) )) {
781 ( $udir ) = $p_dir =~ m|$untaint_pat|;
81793b90 782 unless (defined $udir) {
783 if ($untaint_skip == 0) {
784 die "directory $p_dir is still tainted";
785 }
786 else {
787 return;
788 }
237437d0 789 }
a0d0e21e 790 }
8d8eebbf 791 unless (chdir ($Is_VMS && $udir !~ /[\/\[<]+/ ? "./$udir" : $udir)) {
cd68ec93 792 warnings::warnif "Can't cd to $udir: $!\n";
81793b90 793 return;
794 }
795 }
7e47e6ff 796
797 # push the starting directory
57e73c4b 798 push @Stack,[$CdLvl,$p_dir,$dir_rel,-1] if $bydepth;
81793b90 799
7e47e6ff 800 if ($Is_MacOS) {
801 $p_dir = $dir_pref; # ensure trailing ':'
802 }
803
81793b90 804 while (defined $SE) {
805 unless ($bydepth) {
7e47e6ff 806 $dir= $p_dir; # $File::Find::dir
807 $name= $dir_name; # $File::Find::name
808 $_= ($no_chdir ? $dir_name : $dir_rel ); # $_
81793b90 809 # prune may happen here
7e47e6ff 810 $prune= 0;
abfdd623 811 { $wanted_callback->() }; # protect against wild "next"
7e47e6ff 812 next if $prune;
81793b90 813 }
7e47e6ff 814
81793b90 815 # change to that directory
7e47e6ff 816 unless ($no_chdir || ($dir_rel eq $File::Find::current_dir)) {
81793b90 817 my $udir= $dir_rel;
7e47e6ff 818 if ( ($untaint) && (($tainted) || ($tainted = is_tainted($dir_rel) )) ) {
819 ( $udir ) = $dir_rel =~ m|$untaint_pat|;
81793b90 820 unless (defined $udir) {
821 if ($untaint_skip == 0) {
7e47e6ff 822 if ($Is_MacOS) {
823 die "directory ($p_dir) $dir_rel is still tainted";
824 }
825 else {
826 die "directory (" . ($p_dir ne '/' ? $p_dir : '') . "/) $dir_rel is still tainted";
827 }
828 } else { # $untaint_skip == 1
829 next;
81793b90 830 }
831 }
832 }
8d8eebbf 833 unless (chdir ($Is_VMS && $udir !~ /[\/\[<]+/ ? "./$udir" : $udir)) {
7e47e6ff 834 if ($Is_MacOS) {
cd68ec93 835 warnings::warnif "Can't cd to ($p_dir) $udir: $!\n";
7e47e6ff 836 }
837 else {
cd68ec93 838 warnings::warnif "Can't cd to (" .
839 ($p_dir ne '/' ? $p_dir : '') . "/) $udir: $!\n";
7e47e6ff 840 }
81793b90 841 next;
842 }
843 $CdLvl++;
844 }
845
7e47e6ff 846 if ($Is_MacOS) {
847 $dir_name = "$dir_name:" unless ($dir_name =~ /:$/);
848 }
849
850 $dir= $dir_name; # $File::Find::dir
81793b90 851
852 # Get the list of files in the current directory.
7e47e6ff 853 unless (opendir DIR, ($no_chdir ? $dir_name : $File::Find::current_dir)) {
cd68ec93 854 warnings::warnif "Can't opendir($dir_name): $!\n";
81793b90 855 next;
856 }
857 @filenames = readdir DIR;
858 closedir(DIR);
abfdd623 859 @filenames = $pre_process->(@filenames) if $pre_process;
719c805e 860 push @Stack,[$CdLvl,$dir_name,"",-2] if $post_process;
81793b90 861
5fa2bf2b 862 # default: use whatever was specifid
863 # (if $nlink >= 2, and $avoid_nlink == 0, this will switch back)
864 $no_nlink = $avoid_nlink;
865 # if dir has wrong nlink count, force switch to slower stat method
866 $no_nlink = 1 if ($nlink < 2);
867
868 if ($nlink == 2 && !$no_nlink) {
81793b90 869 # This dir has no subdirectories.
870 for my $FN (@filenames) {
7e47e6ff 871 next if $FN =~ $File::Find::skip_pattern;
81793b90 872
7e47e6ff 873 $name = $dir_pref . $FN; # $File::Find::name
874 $_ = ($no_chdir ? $name : $FN); # $_
abfdd623 875 { $wanted_callback->() }; # protect against wild "next"
81793b90 876 }
877
878 }
879 else {
880 # This dir has subdirectories.
881 $subcount = $nlink - 2;
882
7bd31527 883 # HACK: insert directories at this position. so as to preserve
884 # the user pre-processed ordering of files.
885 # EG: directory traversal is in user sorted order, not at random.
886 my $stack_top = @Stack;
887
81793b90 888 for my $FN (@filenames) {
7e47e6ff 889 next if $FN =~ $File::Find::skip_pattern;
5fa2bf2b 890 if ($subcount > 0 || $no_nlink) {
81793b90 891 # Seen all the subdirs?
892 # check for directoriness.
893 # stat is faster for a file in the current directory
07867069 894 $sub_nlink = (lstat ($no_chdir ? $dir_pref . $FN : $FN))[3];
81793b90 895
896 if (-d _) {
897 --$subcount;
544ff7a7 898 $FN =~ s/\.dir\z//i if $Is_VMS;
7bd31527 899 # HACK: replace push to preserve dir traversal order
900 #push @Stack,[$CdLvl,$dir_name,$FN,$sub_nlink];
901 splice @Stack, $stack_top, 0,
902 [$CdLvl,$dir_name,$FN,$sub_nlink];
81793b90 903 }
904 else {
7e47e6ff 905 $name = $dir_pref . $FN; # $File::Find::name
906 $_= ($no_chdir ? $name : $FN); # $_
abfdd623 907 { $wanted_callback->() }; # protect against wild "next"
81793b90 908 }
909 }
07867069 910 else {
7e47e6ff 911 $name = $dir_pref . $FN; # $File::Find::name
912 $_= ($no_chdir ? $name : $FN); # $_
abfdd623 913 { $wanted_callback->() }; # protect against wild "next"
81793b90 914 }
915 }
916 }
17b275ff 917 }
918 continue {
57e73c4b 919 while ( defined ($SE = pop @Stack) ) {
81793b90 920 ($Level, $p_dir, $dir_rel, $nlink) = @$SE;
921 if ($CdLvl > $Level && !$no_chdir) {
7e47e6ff 922 my $tmp;
923 if ($Is_MacOS) {
924 $tmp = (':' x ($CdLvl-$Level)) . ':';
925 }
926 else {
927 $tmp = join('/',('..') x ($CdLvl-$Level));
928 }
929 die "Can't cd to $dir_name" . $tmp
930 unless chdir ($tmp);
81793b90 931 $CdLvl = $Level;
932 }
7e47e6ff 933
934 if ($Is_MacOS) {
935 # $pdir always has a trailing ':', except for the starting dir,
936 # where $dir_rel eq ':'
937 $dir_name = "$p_dir$dir_rel";
938 $dir_pref = "$dir_name:";
939 }
940 else {
941 $dir_name = ($p_dir eq '/' ? "/$dir_rel" : "$p_dir/$dir_rel");
942 $dir_pref = "$dir_name/";
943 }
944
719c805e 945 if ( $nlink == -2 ) {
7e47e6ff 946 $name = $dir = $p_dir; # $File::Find::name / dir
39e79f6b 947 $_ = $File::Find::current_dir;
abfdd623 948 $post_process->(); # End-of-directory processing
7e47e6ff 949 }
950 elsif ( $nlink < 0 ) { # must be finddepth, report dirname now
951 $name = $dir_name;
952 if ($Is_MacOS) {
953 if ($dir_rel eq ':') { # must be the top dir, where we started
954 $name =~ s|:$||; # $File::Find::name
955 $p_dir = "$p_dir:" unless ($p_dir =~ /:$/);
956 }
957 $dir = $p_dir; # $File::Find::dir
958 $_ = ($no_chdir ? $name : $dir_rel); # $_
959 }
960 else {
961 if ( substr($name,-2) eq '/.' ) {
5cf0a2f2 962 substr($name, length($name) == 2 ? -1 : -2) = '';
7e47e6ff 963 }
964 $dir = $p_dir;
965 $_ = ($no_chdir ? $dir_name : $dir_rel );
966 if ( substr($_,-2) eq '/.' ) {
5cf0a2f2 967 substr($_, length($_) == 2 ? -1 : -2) = '';
7e47e6ff 968 }
969 }
abfdd623 970 { $wanted_callback->() }; # protect against wild "next"
7e47e6ff 971 }
972 else {
973 push @Stack,[$CdLvl,$p_dir,$dir_rel,-1] if $bydepth;
974 last;
975 }
81793b90 976 }
a0d0e21e 977 }
978}
979
81793b90 980
981# API:
982# $wanted
983# $dir_loc : absolute location of a dir
984# $p_dir : "parent directory"
985# preconditions:
986# chdir (if not no_chdir) to dir
987
988sub _find_dir_symlnk($$$) {
7e47e6ff 989 my ($wanted, $dir_loc, $p_dir) = @_; # $dir_loc is the absolute directory
81793b90 990 my @Stack;
991 my @filenames;
992 my $new_loc;
7e47e6ff 993 my $updir_loc = $dir_loc; # untainted parent directory
81793b90 994 my $SE = [];
995 my $dir_name = $p_dir;
7e47e6ff 996 my $dir_pref;
997 my $loc_pref;
39e79f6b 998 my $dir_rel = $File::Find::current_dir;
7e47e6ff 999 my $byd_flag; # flag for pending stack entry if $bydepth
1000 my $tainted = 0;
1001 my $ok = 1;
1002
1003 if ($Is_MacOS) {
1004 $dir_pref = ($p_dir =~ /:$/) ? "$p_dir" : "$p_dir:";
1005 $loc_pref = ($dir_loc =~ /:$/) ? "$dir_loc" : "$dir_loc:";
7e47e6ff 1006 } else {
1007 $dir_pref = ( $p_dir eq '/' ? '/' : "$p_dir/" );
1008 $loc_pref = ( $dir_loc eq '/' ? '/' : "$dir_loc/" );
7e47e6ff 1009 }
81793b90 1010
1011 local ($dir, $name, $fullname, $prune, *DIR);
7e47e6ff 1012
1013 unless ($no_chdir) {
1014 # untaint the topdir
1015 if (( $untaint ) && (is_tainted($dir_loc) )) {
1016 ( $updir_loc ) = $dir_loc =~ m|$untaint_pat|; # parent dir, now untainted
1017 # once untainted, $updir_loc is pushed on the stack (as parent directory);
1018 # hence, we don't need to untaint the parent directory every time we chdir
1019 # to it later
1020 unless (defined $updir_loc) {
81793b90 1021 if ($untaint_skip == 0) {
1022 die "directory $dir_loc is still tainted";
1023 }
1024 else {
1025 return;
1026 }
1027 }
1028 }
7e47e6ff 1029 $ok = chdir($updir_loc) unless ($p_dir eq $File::Find::current_dir);
1030 unless ($ok) {
cd68ec93 1031 warnings::warnif "Can't cd to $updir_loc: $!\n";
81793b90 1032 return;
1033 }
1034 }
1035
7e47e6ff 1036 push @Stack,[$dir_loc,$updir_loc,$p_dir,$dir_rel,-1] if $bydepth;
1037
1038 if ($Is_MacOS) {
1039 $p_dir = $dir_pref; # ensure trailing ':'
1040 }
57e73c4b 1041
81793b90 1042 while (defined $SE) {
1043
1044 unless ($bydepth) {
7e47e6ff 1045 # change (back) to parent directory (always untainted)
704ea872 1046 unless ($no_chdir) {
7e47e6ff 1047 unless (chdir $updir_loc) {
cd68ec93 1048 warnings::warnif "Can't cd to $updir_loc: $!\n";
704ea872 1049 next;
1050 }
1051 }
7e47e6ff 1052 $dir= $p_dir; # $File::Find::dir
1053 $name= $dir_name; # $File::Find::name
1054 $_= ($no_chdir ? $dir_name : $dir_rel ); # $_
1055 $fullname= $dir_loc; # $File::Find::fullname
81793b90 1056 # prune may happen here
7e47e6ff 1057 $prune= 0;
704ea872 1058 lstat($_); # make sure file tests with '_' work
abfdd623 1059 { $wanted_callback->() }; # protect against wild "next"
7e47e6ff 1060 next if $prune;
81793b90 1061 }
1062
1063 # change to that directory
7e47e6ff 1064 unless ($no_chdir || ($dir_rel eq $File::Find::current_dir)) {
1065 $updir_loc = $dir_loc;
1066 if ( ($untaint) && (($tainted) || ($tainted = is_tainted($dir_loc) )) ) {
1067 # untaint $dir_loc, what will be pushed on the stack as (untainted) parent dir
1068 ( $updir_loc ) = $dir_loc =~ m|$untaint_pat|;
1069 unless (defined $updir_loc) {
81793b90 1070 if ($untaint_skip == 0) {
1071 die "directory $dir_loc is still tainted";
a0d0e21e 1072 }
237437d0 1073 else {
81793b90 1074 next;
237437d0 1075 }
a0d0e21e 1076 }
1077 }
7e47e6ff 1078 unless (chdir $updir_loc) {
cd68ec93 1079 warnings::warnif "Can't cd to $updir_loc: $!\n";
81793b90 1080 next;
1081 }
1082 }
1083
7e47e6ff 1084 if ($Is_MacOS) {
1085 $dir_name = "$dir_name:" unless ($dir_name =~ /:$/);
1086 }
1087
1088 $dir = $dir_name; # $File::Find::dir
81793b90 1089
1090 # Get the list of files in the current directory.
7e47e6ff 1091 unless (opendir DIR, ($no_chdir ? $dir_loc : $File::Find::current_dir)) {
cd68ec93 1092 warnings::warnif "Can't opendir($dir_loc): $!\n";
81793b90 1093 next;
1094 }
1095 @filenames = readdir DIR;
1096 closedir(DIR);
1097
1098 for my $FN (@filenames) {
7e47e6ff 1099 next if $FN =~ $File::Find::skip_pattern;
81793b90 1100
1101 # follow symbolic links / do an lstat
07867069 1102 $new_loc = Follow_SymLink($loc_pref.$FN);
81793b90 1103
1104 # ignore if invalid symlink
615a2b9b 1105 unless (defined $new_loc) {
1106 if ($dangling_symlinks) {
1107 if (ref $dangling_symlinks eq 'CODE') {
1108 $dangling_symlinks->($FN, $dir_pref);
1109 } else {
1110 warnings::warnif "$dir_pref$FN is a dangling symbolic link\n";
1111 }
1112 }
1113
1114 $fullname = undef;
1115 $name = $dir_pref . $FN;
1116 $_ = ($no_chdir ? $name : $FN);
1117 { $wanted_callback->() };
1118 next;
1119 }
7e47e6ff 1120
81793b90 1121 if (-d _) {
7e47e6ff 1122 push @Stack,[$new_loc,$updir_loc,$dir_name,$FN,1];
81793b90 1123 }
1124 else {
7e47e6ff 1125 $fullname = $new_loc; # $File::Find::fullname
1126 $name = $dir_pref . $FN; # $File::Find::name
1127 $_ = ($no_chdir ? $name : $FN); # $_
abfdd623 1128 { $wanted_callback->() }; # protect against wild "next"
81793b90 1129 }
1130 }
1131
81793b90 1132 }
1133 continue {
57e73c4b 1134 while (defined($SE = pop @Stack)) {
7e47e6ff 1135 ($dir_loc, $updir_loc, $p_dir, $dir_rel, $byd_flag) = @$SE;
1136 if ($Is_MacOS) {
1137 # $p_dir always has a trailing ':', except for the starting dir,
1138 # where $dir_rel eq ':'
1139 $dir_name = "$p_dir$dir_rel";
1140 $dir_pref = "$dir_name:";
1141 $loc_pref = ($dir_loc =~ /:$/) ? $dir_loc : "$dir_loc:";
1142 }
1143 else {
1144 $dir_name = ($p_dir eq '/' ? "/$dir_rel" : "$p_dir/$dir_rel");
1145 $dir_pref = "$dir_name/";
1146 $loc_pref = "$dir_loc/";
1147 }
1148 if ( $byd_flag < 0 ) { # must be finddepth, report dirname now
1149 unless ($no_chdir || ($dir_rel eq $File::Find::current_dir)) {
1150 unless (chdir $updir_loc) { # $updir_loc (parent dir) is always untainted
cd68ec93 1151 warnings::warnif "Can't cd to $updir_loc: $!\n";
7e47e6ff 1152 next;
1153 }
1154 }
1155 $fullname = $dir_loc; # $File::Find::fullname
1156 $name = $dir_name; # $File::Find::name
1157 if ($Is_MacOS) {
1158 if ($dir_rel eq ':') { # must be the top dir, where we started
1159 $name =~ s|:$||; # $File::Find::name
1160 $p_dir = "$p_dir:" unless ($p_dir =~ /:$/);
1161 }
1162 $dir = $p_dir; # $File::Find::dir
1163 $_ = ($no_chdir ? $name : $dir_rel); # $_
1164 }
1165 else {
1166 if ( substr($name,-2) eq '/.' ) {
f801979b 1167 substr($name, length($name) == 2 ? -1 : -2) = ''; # $File::Find::name
7e47e6ff 1168 }
1169 $dir = $p_dir; # $File::Find::dir
1170 $_ = ($no_chdir ? $dir_name : $dir_rel); # $_
1171 if ( substr($_,-2) eq '/.' ) {
f801979b 1172 substr($_, length($_) == 2 ? -1 : -2) = '';
7e47e6ff 1173 }
1174 }
1175
1176 lstat($_); # make sure file tests with '_' work
abfdd623 1177 { $wanted_callback->() }; # protect against wild "next"
7e47e6ff 1178 }
1179 else {
1180 push @Stack,[$dir_loc, $updir_loc, $p_dir, $dir_rel,-1] if $bydepth;
1181 last;
1182 }
a0d0e21e 1183 }
1184 }
1185}
1186
81793b90 1187
20408e3c 1188sub wrap_wanted {
81793b90 1189 my $wanted = shift;
1190 if ( ref($wanted) eq 'HASH' ) {
1191 if ( $wanted->{follow} || $wanted->{follow_fast}) {
1192 $wanted->{follow_skip} = 1 unless defined $wanted->{follow_skip};
1193 }
1194 if ( $wanted->{untaint} ) {
7e47e6ff 1195 $wanted->{untaint_pattern} = $File::Find::untaint_pattern
81793b90 1196 unless defined $wanted->{untaint_pattern};
1197 $wanted->{untaint_skip} = 0 unless defined $wanted->{untaint_skip};
1198 }
1199 return $wanted;
1200 }
1201 else {
1202 return { wanted => $wanted };
1203 }
a0d0e21e 1204}
1205
20408e3c 1206sub find {
81793b90 1207 my $wanted = shift;
1208 _find_opt(wrap_wanted($wanted), @_);
a0d0e21e 1209}
1210
55d729e4 1211sub finddepth {
81793b90 1212 my $wanted = wrap_wanted(shift);
1213 $wanted->{bydepth} = 1;
1214 _find_opt($wanted, @_);
20408e3c 1215}
6280b799 1216
7e47e6ff 1217# default
1218$File::Find::skip_pattern = qr/^\.{1,2}\z/;
1219$File::Find::untaint_pattern = qr|^([-+@\w./]+)$|;
1220
6280b799 1221# These are hard-coded for now, but may move to hint files.
10eba763 1222if ($^O eq 'VMS') {
81793b90 1223 $Is_VMS = 1;
7e47e6ff 1224 $File::Find::dont_use_nlink = 1;
1225}
1226elsif ($^O eq 'MacOS') {
1227 $Is_MacOS = 1;
1228 $File::Find::dont_use_nlink = 1;
1229 $File::Find::skip_pattern = qr/^Icon\015\z/;
1230 $File::Find::untaint_pattern = qr|^(.+)$|;
748a9306 1231}
1232
7e47e6ff 1233# this _should_ work properly on all platforms
1234# where File::Find can be expected to work
1235$File::Find::current_dir = File::Spec->curdir || '.';
1236
81793b90 1237$File::Find::dont_use_nlink = 1
497711e7 1238 if $^O eq 'os2' || $^O eq 'dos' || $^O eq 'amigaos' || $^O eq 'MSWin32' ||
0c52c6a9 1239 $^O eq 'interix' || $^O eq 'cygwin' || $^O eq 'epoc' || $^O eq 'qnx' ||
1119cb72 1240 $^O eq 'nto';
6280b799 1241
20408e3c 1242# Set dont_use_nlink in your hint file if your system's stat doesn't
1243# report the number of links in a directory as an indication
1244# of the number of files.
1245# See, e.g. hints/machten.sh for MachTen 2.2.
81793b90 1246unless ($File::Find::dont_use_nlink) {
1247 require Config;
1248 $File::Find::dont_use_nlink = 1 if ($Config::Config{'dont_use_nlink'});
20408e3c 1249}
1250
7e47e6ff 1251# We need a function that checks if a scalar is tainted. Either use the
1252# Scalar::Util module's tainted() function or our (slower) pure Perl
1253# fallback is_tainted_pp()
1254{
1255 local $@;
1256 eval { require Scalar::Util };
1257 *is_tainted = $@ ? \&is_tainted_pp : \&Scalar::Util::tainted;
1258}
1259
a0d0e21e 12601;