Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

773 lines
21 KiB

  1. package File::Find;
  2. use 5.005_64;
  3. require Exporter;
  4. require Cwd;
  5. =head1 NAME
  6. find - traverse a file tree
  7. finddepth - traverse a directory structure depth-first
  8. =head1 SYNOPSIS
  9. use File::Find;
  10. find(\&wanted, '/foo', '/bar');
  11. sub wanted { ... }
  12. use File::Find;
  13. finddepth(\&wanted, '/foo', '/bar');
  14. sub wanted { ... }
  15. use File::Find;
  16. find({ wanted => \&process, follow => 1 }, '.');
  17. =head1 DESCRIPTION
  18. The first argument to find() is either a hash reference describing the
  19. operations to be performed for each file, or a code reference.
  20. Here are the possible keys for the hash:
  21. =over 3
  22. =item C<wanted>
  23. The value should be a code reference. This code reference is called
  24. I<the wanted() function> below.
  25. =item C<bydepth>
  26. Reports the name of a directory only AFTER all its entries
  27. have been reported. Entry point finddepth() is a shortcut for
  28. specifying C<{ bydepth => 1 }> in the first argument of find().
  29. =item C<preprocess>
  30. The value should be a code reference. This code reference is used to
  31. preprocess a directory; it is called after readdir() but before the loop that
  32. calls the wanted() function. It is called with a list of strings and is
  33. expected to return a list of strings. The code can be used to sort the
  34. strings alphabetically, numerically, or to filter out directory entries based
  35. on their name alone.
  36. =item C<postprocess>
  37. The value should be a code reference. It is invoked just before leaving the
  38. current directory. It is called in void context with no arguments. The name
  39. of the current directory is in $File::Find::dir. This hook is handy for
  40. summarizing a directory, such as calculating its disk usage.
  41. =item C<follow>
  42. Causes symbolic links to be followed. Since directory trees with symbolic
  43. links (followed) may contain files more than once and may even have
  44. cycles, a hash has to be built up with an entry for each file.
  45. This might be expensive both in space and time for a large
  46. directory tree. See I<follow_fast> and I<follow_skip> below.
  47. If either I<follow> or I<follow_fast> is in effect:
  48. =over 6
  49. =item *
  50. It is guaranteed that an I<lstat> has been called before the user's
  51. I<wanted()> function is called. This enables fast file checks involving S< _>.
  52. =item *
  53. There is a variable C<$File::Find::fullname> which holds the absolute
  54. pathname of the file with all symbolic links resolved
  55. =back
  56. =item C<follow_fast>
  57. This is similar to I<follow> except that it may report some files more
  58. than once. It does detect cycles, however. Since only symbolic links
  59. have to be hashed, this is much cheaper both in space and time. If
  60. processing a file more than once (by the user's I<wanted()> function)
  61. is worse than just taking time, the option I<follow> should be used.
  62. =item C<follow_skip>
  63. C<follow_skip==1>, which is the default, causes all files which are
  64. neither directories nor symbolic links to be ignored if they are about
  65. to be processed a second time. If a directory or a symbolic link
  66. are about to be processed a second time, File::Find dies.
  67. C<follow_skip==0> causes File::Find to die if any file is about to be
  68. processed a second time.
  69. C<follow_skip==2> causes File::Find to ignore any duplicate files and
  70. dirctories but to proceed normally otherwise.
  71. =item C<no_chdir>
  72. Does not C<chdir()> to each directory as it recurses. The wanted()
  73. function will need to be aware of this, of course. In this case,
  74. C<$_> will be the same as C<$File::Find::name>.
  75. =item C<untaint>
  76. If find is used in taint-mode (-T command line switch or if EUID != UID
  77. or if EGID != GID) then internally directory names have to be untainted
  78. before they can be cd'ed to. Therefore they are checked against a regular
  79. expression I<untaint_pattern>. Note that all names passed to the
  80. user's I<wanted()> function are still tainted.
  81. =item C<untaint_pattern>
  82. See above. This should be set using the C<qr> quoting operator.
  83. The default is set to C<qr|^([-+@\w./]+)$|>.
  84. Note that the parantheses are vital.
  85. =item C<untaint_skip>
  86. If set, directories (subtrees) which fail the I<untaint_pattern>
  87. are skipped. The default is to 'die' in such a case.
  88. =back
  89. The wanted() function does whatever verifications you want.
  90. C<$File::Find::dir> contains the current directory name, and C<$_> the
  91. current filename within that directory. C<$File::Find::name> contains
  92. the complete pathname to the file. You are chdir()'d to
  93. C<$File::Find::dir> when the function is called, unless C<no_chdir>
  94. was specified. When <follow> or <follow_fast> are in effect, there is
  95. also a C<$File::Find::fullname>. The function may set
  96. C<$File::Find::prune> to prune the tree unless C<bydepth> was
  97. specified. Unless C<follow> or C<follow_fast> is specified, for
  98. compatibility reasons (find.pl, find2perl) there are in addition the
  99. following globals available: C<$File::Find::topdir>,
  100. C<$File::Find::topdev>, C<$File::Find::topino>,
  101. C<$File::Find::topmode> and C<$File::Find::topnlink>.
  102. This library is useful for the C<find2perl> tool, which when fed,
  103. find2perl / -name .nfs\* -mtime +7 \
  104. -exec rm -f {} \; -o -fstype nfs -prune
  105. produces something like:
  106. sub wanted {
  107. /^\.nfs.*\z/s &&
  108. (($dev, $ino, $mode, $nlink, $uid, $gid) = lstat($_)) &&
  109. int(-M _) > 7 &&
  110. unlink($_)
  111. ||
  112. ($nlink || (($dev, $ino, $mode, $nlink, $uid, $gid) = lstat($_))) &&
  113. $dev < 0 &&
  114. ($File::Find::prune = 1);
  115. }
  116. Set the variable C<$File::Find::dont_use_nlink> if you're using AFS,
  117. since AFS cheats.
  118. Here's another interesting wanted function. It will find all symlinks
  119. that don't resolve:
  120. sub wanted {
  121. -l && !-e && print "bogus link: $File::Find::name\n";
  122. }
  123. See also the script C<pfind> on CPAN for a nice application of this
  124. module.
  125. =head1 CAVEAT
  126. Be aware that the option to follow symbolic links can be dangerous.
  127. Depending on the structure of the directory tree (including symbolic
  128. links to directories) you might traverse a given (physical) directory
  129. more than once (only if C<follow_fast> is in effect).
  130. Furthermore, deleting or changing files in a symbolically linked directory
  131. might cause very unpleasant surprises, since you delete or change files
  132. in an unknown directory.
  133. =cut
  134. @ISA = qw(Exporter);
  135. @EXPORT = qw(find finddepth);
  136. use strict;
  137. my $Is_VMS;
  138. require File::Basename;
  139. my %SLnkSeen;
  140. my ($wanted_callback, $avoid_nlink, $bydepth, $no_chdir, $follow,
  141. $follow_skip, $full_check, $untaint, $untaint_skip, $untaint_pat,
  142. $pre_process, $post_process);
  143. sub contract_name {
  144. my ($cdir,$fn) = @_;
  145. return substr($cdir,0,rindex($cdir,'/')) if $fn eq '.';
  146. $cdir = substr($cdir,0,rindex($cdir,'/')+1);
  147. $fn =~ s|^\./||;
  148. my $abs_name= $cdir . $fn;
  149. if (substr($fn,0,3) eq '../') {
  150. do 1 while ($abs_name=~ s|/(?>[^/]+)/\.\./|/|);
  151. }
  152. return $abs_name;
  153. }
  154. sub PathCombine($$) {
  155. my ($Base,$Name) = @_;
  156. my $AbsName;
  157. if (substr($Name,0,1) eq '/') {
  158. $AbsName= $Name;
  159. }
  160. else {
  161. $AbsName= contract_name($Base,$Name);
  162. }
  163. # (simple) check for recursion
  164. my $newlen= length($AbsName);
  165. if ($newlen <= length($Base)) {
  166. if (($newlen == length($Base) || substr($Base,$newlen,1) eq '/')
  167. && $AbsName eq substr($Base,0,$newlen))
  168. {
  169. return undef;
  170. }
  171. }
  172. return $AbsName;
  173. }
  174. sub Follow_SymLink($) {
  175. my ($AbsName) = @_;
  176. my ($NewName,$DEV, $INO);
  177. ($DEV, $INO)= lstat $AbsName;
  178. while (-l _) {
  179. if ($SLnkSeen{$DEV, $INO}++) {
  180. if ($follow_skip < 2) {
  181. die "$AbsName is encountered a second time";
  182. }
  183. else {
  184. return undef;
  185. }
  186. }
  187. $NewName= PathCombine($AbsName, readlink($AbsName));
  188. unless(defined $NewName) {
  189. if ($follow_skip < 2) {
  190. die "$AbsName is a recursive symbolic link";
  191. }
  192. else {
  193. return undef;
  194. }
  195. }
  196. else {
  197. $AbsName= $NewName;
  198. }
  199. ($DEV, $INO) = lstat($AbsName);
  200. return undef unless defined $DEV; # dangling symbolic link
  201. }
  202. if ($full_check && $SLnkSeen{$DEV, $INO}++) {
  203. if ($follow_skip < 1) {
  204. die "$AbsName encountered a second time";
  205. }
  206. else {
  207. return undef;
  208. }
  209. }
  210. return $AbsName;
  211. }
  212. our($dir, $name, $fullname, $prune);
  213. sub _find_dir_symlnk($$$);
  214. sub _find_dir($$$);
  215. sub _find_opt {
  216. my $wanted = shift;
  217. die "invalid top directory" unless defined $_[0];
  218. my $cwd = $wanted->{bydepth} ? Cwd::fastcwd() : Cwd::cwd();
  219. my $cwd_untainted = $cwd;
  220. $wanted_callback = $wanted->{wanted};
  221. $bydepth = $wanted->{bydepth};
  222. $pre_process = $wanted->{preprocess};
  223. $post_process = $wanted->{postprocess};
  224. $no_chdir = $wanted->{no_chdir};
  225. $full_check = $wanted->{follow};
  226. $follow = $full_check || $wanted->{follow_fast};
  227. $follow_skip = $wanted->{follow_skip};
  228. $untaint = $wanted->{untaint};
  229. $untaint_pat = $wanted->{untaint_pattern};
  230. $untaint_skip = $wanted->{untaint_skip};
  231. # for compatability reasons (find.pl, find2perl)
  232. our ($topdir, $topdev, $topino, $topmode, $topnlink);
  233. # a symbolic link to a directory doesn't increase the link count
  234. $avoid_nlink = $follow || $File::Find::dont_use_nlink;
  235. if ( $untaint ) {
  236. $cwd_untainted= $1 if $cwd_untainted =~ m|$untaint_pat|;
  237. die "insecure cwd in find(depth)" unless defined($cwd_untainted);
  238. }
  239. my ($abs_dir, $Is_Dir);
  240. Proc_Top_Item:
  241. foreach my $TOP (@_) {
  242. my $top_item = $TOP;
  243. $top_item =~ s|/\z|| unless $top_item eq '/';
  244. $Is_Dir= 0;
  245. ($topdev,$topino,$topmode,$topnlink) = stat $top_item;
  246. if ($follow) {
  247. if (substr($top_item,0,1) eq '/') {
  248. $abs_dir = $top_item;
  249. }
  250. elsif ($top_item eq '.') {
  251. $abs_dir = $cwd;
  252. }
  253. else { # care about any ../
  254. $abs_dir = contract_name("$cwd/",$top_item);
  255. }
  256. $abs_dir= Follow_SymLink($abs_dir);
  257. unless (defined $abs_dir) {
  258. warn "$top_item is a dangling symbolic link\n";
  259. next Proc_Top_Item;
  260. }
  261. if (-d _) {
  262. _find_dir_symlnk($wanted, $abs_dir, $top_item);
  263. $Is_Dir= 1;
  264. }
  265. }
  266. else { # no follow
  267. $topdir = $top_item;
  268. unless (defined $topnlink) {
  269. warn "Can't stat $top_item: $!\n";
  270. next Proc_Top_Item;
  271. }
  272. if (-d _) {
  273. $top_item =~ s/\.dir\z// if $Is_VMS;
  274. _find_dir($wanted, $top_item, $topnlink);
  275. $Is_Dir= 1;
  276. }
  277. else {
  278. $abs_dir= $top_item;
  279. }
  280. }
  281. unless ($Is_Dir) {
  282. unless (($_,$dir) = File::Basename::fileparse($abs_dir)) {
  283. ($dir,$_) = ('./', $top_item);
  284. }
  285. $abs_dir = $dir;
  286. if ($untaint) {
  287. my $abs_dir_save = $abs_dir;
  288. $abs_dir = $1 if $abs_dir =~ m|$untaint_pat|;
  289. unless (defined $abs_dir) {
  290. if ($untaint_skip == 0) {
  291. die "directory $abs_dir_save is still tainted";
  292. }
  293. else {
  294. next Proc_Top_Item;
  295. }
  296. }
  297. }
  298. unless ($no_chdir or chdir $abs_dir) {
  299. warn "Couldn't chdir $abs_dir: $!\n";
  300. next Proc_Top_Item;
  301. }
  302. $name = $abs_dir . $_;
  303. { &$wanted_callback }; # protect against wild "next"
  304. }
  305. $no_chdir or chdir $cwd_untainted;
  306. }
  307. }
  308. # API:
  309. # $wanted
  310. # $p_dir : "parent directory"
  311. # $nlink : what came back from the stat
  312. # preconditions:
  313. # chdir (if not no_chdir) to dir
  314. sub _find_dir($$$) {
  315. my ($wanted, $p_dir, $nlink) = @_;
  316. my ($CdLvl,$Level) = (0,0);
  317. my @Stack;
  318. my @filenames;
  319. my ($subcount,$sub_nlink);
  320. my $SE= [];
  321. my $dir_name= $p_dir;
  322. my $dir_pref= ( $p_dir eq '/' ? '/' : "$p_dir/" );
  323. my $dir_rel= '.'; # directory name relative to current directory
  324. local ($dir, $name, $prune, *DIR);
  325. unless ($no_chdir or $p_dir eq '.') {
  326. my $udir = $p_dir;
  327. if ($untaint) {
  328. $udir = $1 if $p_dir =~ m|$untaint_pat|;
  329. unless (defined $udir) {
  330. if ($untaint_skip == 0) {
  331. die "directory $p_dir is still tainted";
  332. }
  333. else {
  334. return;
  335. }
  336. }
  337. }
  338. unless (chdir $udir) {
  339. warn "Can't cd to $udir: $!\n";
  340. return;
  341. }
  342. }
  343. push @Stack,[$CdLvl,$p_dir,$dir_rel,-1] if $bydepth;
  344. while (defined $SE) {
  345. unless ($bydepth) {
  346. $dir= $p_dir;
  347. $name= $dir_name;
  348. $_= ($no_chdir ? $dir_name : $dir_rel );
  349. # prune may happen here
  350. $prune= 0;
  351. { &$wanted_callback }; # protect against wild "next"
  352. next if $prune;
  353. }
  354. # change to that directory
  355. unless ($no_chdir or $dir_rel eq '.') {
  356. my $udir= $dir_rel;
  357. if ($untaint) {
  358. $udir = $1 if $dir_rel =~ m|$untaint_pat|;
  359. unless (defined $udir) {
  360. if ($untaint_skip == 0) {
  361. die "directory ("
  362. . ($p_dir ne '/' ? $p_dir : '')
  363. . "/) $dir_rel is still tainted";
  364. }
  365. }
  366. }
  367. unless (chdir $udir) {
  368. warn "Can't cd to ("
  369. . ($p_dir ne '/' ? $p_dir : '')
  370. . "/) $udir : $!\n";
  371. next;
  372. }
  373. $CdLvl++;
  374. }
  375. $dir= $dir_name;
  376. # Get the list of files in the current directory.
  377. unless (opendir DIR, ($no_chdir ? $dir_name : '.')) {
  378. warn "Can't opendir($dir_name): $!\n";
  379. next;
  380. }
  381. @filenames = readdir DIR;
  382. closedir(DIR);
  383. @filenames = &$pre_process(@filenames) if $pre_process;
  384. push @Stack,[$CdLvl,$dir_name,"",-2] if $post_process;
  385. if ($nlink == 2 && !$avoid_nlink) {
  386. # This dir has no subdirectories.
  387. for my $FN (@filenames) {
  388. next if $FN =~ /^\.{1,2}\z/;
  389. $name = $dir_pref . $FN;
  390. $_ = ($no_chdir ? $name : $FN);
  391. { &$wanted_callback }; # protect against wild "next"
  392. }
  393. }
  394. else {
  395. # This dir has subdirectories.
  396. $subcount = $nlink - 2;
  397. for my $FN (@filenames) {
  398. next if $FN =~ /^\.{1,2}\z/;
  399. if ($subcount > 0 || $avoid_nlink) {
  400. # Seen all the subdirs?
  401. # check for directoriness.
  402. # stat is faster for a file in the current directory
  403. $sub_nlink = (lstat ($no_chdir ? $dir_pref . $FN : $FN))[3];
  404. if (-d _) {
  405. --$subcount;
  406. $FN =~ s/\.dir\z// if $Is_VMS;
  407. push @Stack,[$CdLvl,$dir_name,$FN,$sub_nlink];
  408. }
  409. else {
  410. $name = $dir_pref . $FN;
  411. $_= ($no_chdir ? $name : $FN);
  412. { &$wanted_callback }; # protect against wild "next"
  413. }
  414. }
  415. else {
  416. $name = $dir_pref . $FN;
  417. $_= ($no_chdir ? $name : $FN);
  418. { &$wanted_callback }; # protect against wild "next"
  419. }
  420. }
  421. }
  422. }
  423. continue {
  424. while ( defined ($SE = pop @Stack) ) {
  425. ($Level, $p_dir, $dir_rel, $nlink) = @$SE;
  426. if ($CdLvl > $Level && !$no_chdir) {
  427. my $tmp = join('/',('..') x ($CdLvl-$Level));
  428. die "Can't cd to $dir_name" . $tmp
  429. unless chdir ($tmp);
  430. $CdLvl = $Level;
  431. }
  432. $dir_name = ($p_dir eq '/' ? "/$dir_rel" : "$p_dir/$dir_rel");
  433. $dir_pref = "$dir_name/";
  434. if ( $nlink == -2 ) {
  435. $name = $dir = $p_dir;
  436. $_ = ".";
  437. &$post_process; # End-of-directory processing
  438. } elsif ( $nlink < 0 ) { # must be finddepth, report dirname now
  439. $name = $dir_name;
  440. if ( substr($name,-2) eq '/.' ) {
  441. $name =~ s|/\.$||;
  442. }
  443. $dir = $p_dir;
  444. $_ = ($no_chdir ? $dir_name : $dir_rel );
  445. if ( substr($_,-2) eq '/.' ) {
  446. s|/\.$||;
  447. }
  448. { &$wanted_callback }; # protect against wild "next"
  449. } else {
  450. push @Stack,[$CdLvl,$p_dir,$dir_rel,-1] if $bydepth;
  451. last;
  452. }
  453. }
  454. }
  455. }
  456. # API:
  457. # $wanted
  458. # $dir_loc : absolute location of a dir
  459. # $p_dir : "parent directory"
  460. # preconditions:
  461. # chdir (if not no_chdir) to dir
  462. sub _find_dir_symlnk($$$) {
  463. my ($wanted, $dir_loc, $p_dir) = @_;
  464. my @Stack;
  465. my @filenames;
  466. my $new_loc;
  467. my $pdir_loc = $dir_loc;
  468. my $SE = [];
  469. my $dir_name = $p_dir;
  470. my $dir_pref = ( $p_dir eq '/' ? '/' : "$p_dir/" );
  471. my $loc_pref = ( $dir_loc eq '/' ? '/' : "$dir_loc/" );
  472. my $dir_rel = '.'; # directory name relative to current directory
  473. my $byd_flag; # flag for pending stack entry if $bydepth
  474. local ($dir, $name, $fullname, $prune, *DIR);
  475. unless ($no_chdir or $p_dir eq '.') {
  476. my $udir = $dir_loc;
  477. if ($untaint) {
  478. $udir = $1 if $dir_loc =~ m|$untaint_pat|;
  479. unless (defined $udir) {
  480. if ($untaint_skip == 0) {
  481. die "directory $dir_loc is still tainted";
  482. }
  483. else {
  484. return;
  485. }
  486. }
  487. }
  488. unless (chdir $udir) {
  489. warn "Can't cd to $udir: $!\n";
  490. return;
  491. }
  492. }
  493. push @Stack,[$dir_loc,$pdir_loc,$p_dir,$dir_rel,-1] if $bydepth;
  494. while (defined $SE) {
  495. unless ($bydepth) {
  496. # change to parent directory
  497. unless ($no_chdir) {
  498. my $udir = $pdir_loc;
  499. if ($untaint) {
  500. $udir = $1 if $pdir_loc =~ m|$untaint_pat|;
  501. }
  502. unless (chdir $udir) {
  503. warn "Can't cd to $udir: $!\n";
  504. next;
  505. }
  506. }
  507. $dir= $p_dir;
  508. $name= $dir_name;
  509. $_= ($no_chdir ? $dir_name : $dir_rel );
  510. $fullname= $dir_loc;
  511. # prune may happen here
  512. $prune= 0;
  513. lstat($_); # make sure file tests with '_' work
  514. { &$wanted_callback }; # protect against wild "next"
  515. next if $prune;
  516. }
  517. # change to that directory
  518. unless ($no_chdir or $dir_rel eq '.') {
  519. my $udir = $dir_loc;
  520. if ($untaint) {
  521. $udir = $1 if $dir_loc =~ m|$untaint_pat|;
  522. unless (defined $udir ) {
  523. if ($untaint_skip == 0) {
  524. die "directory $dir_loc is still tainted";
  525. }
  526. else {
  527. next;
  528. }
  529. }
  530. }
  531. unless (chdir $udir) {
  532. warn "Can't cd to $udir: $!\n";
  533. next;
  534. }
  535. }
  536. $dir = $dir_name;
  537. # Get the list of files in the current directory.
  538. unless (opendir DIR, ($no_chdir ? $dir_loc : '.')) {
  539. warn "Can't opendir($dir_loc): $!\n";
  540. next;
  541. }
  542. @filenames = readdir DIR;
  543. closedir(DIR);
  544. for my $FN (@filenames) {
  545. next if $FN =~ /^\.{1,2}\z/;
  546. # follow symbolic links / do an lstat
  547. $new_loc = Follow_SymLink($loc_pref.$FN);
  548. # ignore if invalid symlink
  549. next unless defined $new_loc;
  550. if (-d _) {
  551. push @Stack,[$new_loc,$dir_loc,$dir_name,$FN,1];
  552. }
  553. else {
  554. $fullname = $new_loc;
  555. $name = $dir_pref . $FN;
  556. $_ = ($no_chdir ? $name : $FN);
  557. { &$wanted_callback }; # protect against wild "next"
  558. }
  559. }
  560. }
  561. continue {
  562. while (defined($SE = pop @Stack)) {
  563. ($dir_loc, $pdir_loc, $p_dir, $dir_rel, $byd_flag) = @$SE;
  564. $dir_name = ($p_dir eq '/' ? "/$dir_rel" : "$p_dir/$dir_rel");
  565. $dir_pref = "$dir_name/";
  566. $loc_pref = "$dir_loc/";
  567. if ( $byd_flag < 0 ) { # must be finddepth, report dirname now
  568. unless ($no_chdir or $dir_rel eq '.') {
  569. my $udir = $pdir_loc;
  570. if ($untaint) {
  571. $udir = $1 if $dir_loc =~ m|$untaint_pat|;
  572. }
  573. unless (chdir $udir) {
  574. warn "Can't cd to $udir: $!\n";
  575. next;
  576. }
  577. }
  578. $fullname = $dir_loc;
  579. $name = $dir_name;
  580. if ( substr($name,-2) eq '/.' ) {
  581. $name =~ s|/\.$||;
  582. }
  583. $dir = $p_dir;
  584. $_ = ($no_chdir ? $dir_name : $dir_rel);
  585. if ( substr($_,-2) eq '/.' ) {
  586. s|/\.$||;
  587. }
  588. lstat($_); # make sure file tests with '_' work
  589. { &$wanted_callback }; # protect against wild "next"
  590. } else {
  591. push @Stack,[$dir_loc, $pdir_loc, $p_dir, $dir_rel,-1] if $bydepth;
  592. last;
  593. }
  594. }
  595. }
  596. }
  597. sub wrap_wanted {
  598. my $wanted = shift;
  599. if ( ref($wanted) eq 'HASH' ) {
  600. if ( $wanted->{follow} || $wanted->{follow_fast}) {
  601. $wanted->{follow_skip} = 1 unless defined $wanted->{follow_skip};
  602. }
  603. if ( $wanted->{untaint} ) {
  604. $wanted->{untaint_pattern} = qr|^([-+@\w./]+)$|
  605. unless defined $wanted->{untaint_pattern};
  606. $wanted->{untaint_skip} = 0 unless defined $wanted->{untaint_skip};
  607. }
  608. return $wanted;
  609. }
  610. else {
  611. return { wanted => $wanted };
  612. }
  613. }
  614. sub find {
  615. my $wanted = shift;
  616. _find_opt(wrap_wanted($wanted), @_);
  617. %SLnkSeen= (); # free memory
  618. }
  619. sub finddepth {
  620. my $wanted = wrap_wanted(shift);
  621. $wanted->{bydepth} = 1;
  622. _find_opt($wanted, @_);
  623. %SLnkSeen= (); # free memory
  624. }
  625. # These are hard-coded for now, but may move to hint files.
  626. if ($^O eq 'VMS') {
  627. $Is_VMS = 1;
  628. $File::Find::dont_use_nlink = 1;
  629. }
  630. $File::Find::dont_use_nlink = 1
  631. if $^O eq 'os2' || $^O eq 'dos' || $^O eq 'amigaos' || $^O eq 'MSWin32' ||
  632. $^O eq 'cygwin' || $^O eq 'epoc';
  633. # Set dont_use_nlink in your hint file if your system's stat doesn't
  634. # report the number of links in a directory as an indication
  635. # of the number of files.
  636. # See, e.g. hints/machten.sh for MachTen 2.2.
  637. unless ($File::Find::dont_use_nlink) {
  638. require Config;
  639. $File::Find::dont_use_nlink = 1 if ($Config::Config{'dont_use_nlink'});
  640. }
  641. 1;