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