File Coverage

blib/lib/Filesys/POSIX/Userland/Find.pm
Criterion Covered Total %
statement 36 36 100.0
branch 10 10 100.0
condition 3 3 100.0
subroutine 6 6 100.0
pod 1 1 100.0
total 56 56 100.0


line stmt bran cond sub pod time code
1             # Copyright (c) 2014, cPanel, Inc.
2             # All rights reserved.
3             # http://cpanel.net/
4             #
5             # This is free software; you can redistribute it and/or modify it under the same
6             # terms as Perl itself. See the LICENSE file for further details.
7              
8             package Filesys::POSIX::Userland::Find;
9              
10 8     8   425 use strict;
  8         8  
  8         224  
11 8     8   29 use warnings;
  8         9  
  8         140  
12              
13 8     8   20 use Filesys::POSIX::Bits;
  8         8  
  8         2234  
14 8     8   35 use Filesys::POSIX::Module ();
  8         9  
  8         96  
15 8     8   177 use Filesys::POSIX::Path ();
  8         13  
  8         2041  
16              
17             my @METHODS = qw(find);
18              
19             Filesys::POSIX::Module->export_methods( __PACKAGE__, @METHODS );
20              
21             =head1 NAME
22              
23             Filesys::POSIX::Userland::Find - Crawl directories in a filesystem
24              
25             =head1 SYNOPSIS
26              
27             use Filesys::POSIX;
28             use Filesys::POSIX::Real;
29             use Filesys::POSIX::Userland::Find;
30              
31             my $fs = Filesys::POSIX->new(Filesys::POSIX::Real->new,
32             'special' => 'real:/home/foo',
33             'noatime' => 1
34             );
35              
36             $fs->find(sub {
37             my ($path, $inode) = @_;
38             printf("0%o %s\n", $inode->{'mode'}, $path->full);
39             }, '/');
40              
41             =head1 DESCRIPTION
42              
43             This module provides an extension module to L that operates
44             very similarly in principle to the Perl Core module L, albeit with
45             some minor differences and fewer options. For the sake of efficiency, tail
46             recursion, rather than pure call recursion, is used to handle very deep
47             hierarchies.
48              
49             =head1 USAGE
50              
51             =over
52              
53             =item C<$fs-Efind($callback, @paths)>
54              
55             =item C<$fs-Efind($callback, $options, @paths)>
56              
57             C<$fs-Efind> will perform recursive descent into each path passed, printing
58             the full pathname of each item found relative to each item found in the
59             C<@paths> list. For each item found, both a Filesys::POSIX::Path object, and an
60             inode, respectively, are passed as the sole arguments to the callback. With
61             this mechanism, it is possible to retrieve path data from each item in every way
62             currently provided by L, without retaining global state to do so.
63             As a reference to the corresponding item's inode object is passed, there is no
64             need to perform a C<$fs-Estat> call to further inspect the item.
65              
66             When called with an C<$options> argument, specified in the form of an anonymous
67             HASH, the following flags (whose values are set nonzero) are honored:
68              
69             =over
70              
71             =item C
72              
73             Any symlinks found along the way are resolved; if the paths they resolve to are
74             those of directories, then further descent will be made into said directories.
75              
76             =back
77              
78             =back
79              
80             =cut
81              
82             sub find {
83 14     14 1 924 my $self = shift;
84 14         32 my $callback = shift;
85 14 100       62 my %opts = ref $_[0] eq 'HASH' ? %{ (shift) } : ();
  13         51  
86 14         38 my @args = @_;
87              
88 14         87 my @paths = map { Filesys::POSIX::Path->new($_) } @args;
  14         180  
89 14         42 my @inodes = map { $self->lstat($_) } @args;
  14         141  
90              
91 14         56 while ( my $inode = pop @inodes ) {
92 118         116 my $path = pop @paths;
93              
94 118 100       245 if ( $inode->link ) {
95 6 100       23 $inode = $self->stat( $inode->readlink ) if $opts{'follow'};
96             }
97              
98 118         259 $callback->( $path, $inode );
99              
100 117 100       272 if ( $inode->dir ) {
101 68         133 my $directory = $inode->directory->open;
102              
103 68         152 while ( defined( my $item = $directory->read ) ) {
104 240 100 100     874 next if $item eq '.' || $item eq '..';
105 104         223 push @paths, Filesys::POSIX::Path->new( $path->full . "/$item" );
106 104         289 push @inodes, $self->{'vfs'}->vnode( $directory->get($item) );
107             }
108              
109 68         143 $directory->close;
110             }
111             }
112             }
113              
114             1;
115              
116             __END__