File Coverage

blib/lib/Filesys/POSIX/Userland.pm
Criterion Covered Total %
statement 66 66 100.0
branch 12 12 100.0
condition 3 3 100.0
subroutine 14 14 100.0
pod 7 7 100.0
total 102 102 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;
9              
10 25     25   79 use strict;
  25         27  
  25         530  
11 25     25   84 use warnings;
  25         23  
  25         457  
12              
13 25     25   77 use Filesys::POSIX::Bits;
  25         18  
  25         5581  
14 25     25   99 use Filesys::POSIX::Module ();
  25         19  
  25         271  
15 25     25   63 use Filesys::POSIX::Path ();
  25         24  
  25         347  
16              
17 25     25   68 use Carp qw(confess);
  25         22  
  25         12359  
18              
19             my @METHODS = qw(
20             _find_inode_path mkpath getcwd realpath opendir readdir closedir touch
21             );
22              
23             Filesys::POSIX::Module->export_methods( __PACKAGE__, @METHODS );
24              
25             =head1 NAME
26              
27             Filesys::POSIX::Userland - Provide implementations for higher-level, "userland"
28             functionality in L
29              
30             =head1 DESCRIPTION
31              
32             This module is a mixin imported by L into its own namespace, and
33             provides a variety of higher-level calls to supplement the normal suite of
34             system calls provided in L itself.
35              
36             =head1 METHODS
37              
38             =over
39              
40             =cut
41              
42             sub _find_inode_path {
43 23     23   21 my ( $self, $start ) = @_;
44 23         39 my $inode = $self->{'vfs'}->vnode($start);
45 23         20 my @ret;
46              
47 23         60 while ( my $dir = $self->{'vfs'}->vnode($inode)->{'parent'} ) {
48 41         67 my $directory = $dir->directory;
49              
50 41         67 foreach my $item ( $directory->list ) {
51 187 100 100     511 next if $item eq '.' || $item eq '..';
52             next
53 105 100       167 unless $self->{'vfs'}->vnode( $directory->get($item) ) == $self->{'vfs'}->vnode($inode);
54              
55 41         49 push @ret, $item;
56 41         50 $inode = $dir;
57             }
58             }
59              
60 23         89 return '/' . join( '/', reverse @ret );
61             }
62              
63             =item C<$fs-Emkpath($path)>
64              
65             =item C<$fs-Emkpath($path, $mode)>
66              
67             Similar to the C<-p> flag that can be passed to L, this
68             method attempts to create a hierarchy of directories specified in C<$path>.
69             Each path component created will be made with the mode specified by C<$mode>, if
70             any, if a directory in that location does not already exist. Exceptions will be
71             thrown if one of the items along the path hierarchy exists but is not a
72             directory.
73              
74             A default mode of 0777 is assumed; only the permissions field of C<$mode> is
75             used when it is specified. In both cases, the mode specified is modified with
76             exclusive OR by the current umask value.
77              
78             =cut
79              
80             sub mkpath {
81 20     20 1 7669 my ( $self, $path, $mode ) = @_;
82 20 100       64 my $perm = $mode ? $mode & ( $S_IPERM | $S_IPROT ) : $S_IPERM ^ $self->{'umask'};
83 20         74 my $hier = Filesys::POSIX::Path->new($path);
84 20         32 my $dir = $self->{'cwd'};
85              
86 20         50 while ( $hier->count ) {
87 95         137 my $item = $hier->shift;
88              
89 95 100       161 unless ($item) {
90 11         10 $dir = $self->{'root'};
91 11         22 next;
92             }
93              
94 84         145 my $directory = $dir->directory;
95 84         166 my $inode = $self->{'vfs'}->vnode( $directory->get($item) );
96              
97 84 100       102 if ($inode) {
98 11         24 $dir = $inode;
99             }
100             else {
101 73         143 $dir = $dir->child( $item, $perm | $S_IFDIR );
102             }
103             }
104              
105 20         59 return $dir;
106             }
107              
108             =item C<$fs-Egetcwd>
109              
110             Returns a string representation of the current working directory.
111              
112             =cut
113              
114             sub getcwd {
115 7     7 1 291 my ($self) = @_;
116              
117 7         14 return $self->_find_inode_path( $self->{'cwd'} );
118             }
119              
120             =item C<$fs-Erealpath($path)>
121              
122             Returns a string representation of the full, true and original path of the
123             inode specified by C<$path>.
124              
125             Using C<$fs-Estat>, the inode of C<$path> is resolved, then starting at that
126             inode, each subsequent inode's name is found from its parent and appended to a
127             list of path components.
128              
129             =cut
130              
131             sub realpath {
132 2     2 1 542 my ( $self, $path ) = @_;
133 2         5 my $inode = $self->stat($path);
134              
135 2         4 return $self->_find_inode_path($inode);
136             }
137              
138             =item C<$fs-Eopendir($path)>
139              
140             Returns a newly opened directory handle for the item pointed to by C<$path>.
141             Using other methods in this module, the directory can be read and closed.
142              
143             =cut
144              
145             sub opendir {
146 4     4 1 551 my ( $self, $path ) = @_;
147              
148 4         11 my $directory = $self->stat($path)->directory;
149 4         12 $directory->open;
150              
151 4         6 return $directory;
152             }
153              
154             =item C<$fs-Ereaddir($directory)>
155              
156             Read the next member of the directory passed. Returns undef if there are no
157             more entries to be read.
158              
159             =cut
160              
161             sub readdir {
162 14     14 1 43 my ( $self, $directory ) = @_;
163              
164 14 100       33 return $directory->read unless wantarray;
165              
166 2         2 my @ret;
167              
168 2         6 while ( defined( my $item = $directory->read ) ) {
169 10         23 push @ret, $item;
170             }
171              
172 2         6 return @ret;
173             }
174              
175             =item C<$fs-Eclosedir($directory)>
176              
177             Closes the directory handle for reading.
178              
179             =cut
180              
181             sub closedir {
182 4     4 1 23 my ( $self, $directory ) = @_;
183 4         9 return $directory->close;
184             }
185              
186             =item C<$fs-Etouch($path)>
187              
188             Acts like the userland utility L. Uses C<$fs-Eopen>
189             with the C<$O_CREAT> flag to open the file specified by C<$path>, and
190             immediately closes the file descriptor returned. This causes an update of the
191             inode modification time for existing files, and the creation of new, empty files
192             otherwise.
193              
194             =cut
195              
196             sub touch {
197 27     27 1 1761 my ( $self, $path ) = @_;
198 27         73 my $fd = $self->open( $path, $O_CREAT );
199 27         61 my $inode = $self->fstat($fd);
200              
201 27         62 $self->close($fd);
202              
203 27         43 return $inode;
204             }
205              
206             =back
207              
208             =cut
209              
210             1;
211              
212             __END__