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