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 24     24   90 use strict;
  24         30  
  24         1321  
11 24     24   768 use warnings;
  24         26  
  24         2067  
12              
13 24     24   78 use Filesys::POSIX::Bits;
  24         44  
  24         6550  
14 24     24   112 use Filesys::POSIX::Module ();
  24         23  
  24         264  
15 24     24   77 use Filesys::POSIX::Path ();
  24         730  
  24         371  
16              
17 24     24   76 use Carp qw(confess);
  24         23  
  24         12886  
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 22     22   26 my ( $self, $start ) = @_;
44 22         50 my $inode = $self->{'vfs'}->vnode($start);
45 22         28 my @ret;
46              
47 22         59 while ( my $dir = $self->{'vfs'}->vnode($inode)->{'parent'} ) {
48 39         107 my $directory = $dir->directory;
49              
50 39         113 foreach my $item ( $directory->list ) {
51 178 100 100     583 next if $item eq '.' || $item eq '..';
52             next
53 100 100       190 unless $self->{'vfs'}->vnode( $directory->get($item) ) == $self->{'vfs'}->vnode($inode);
54              
55 39         56 push @ret, $item;
56 39         54 $inode = $dir;
57             }
58             }
59              
60 22         102 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 9192 my ( $self, $path, $mode ) = @_;
82 20 100       86 my $perm = $mode ? $mode & ( $S_IPERM | $S_IPROT ) : $S_IPERM ^ $self->{'umask'};
83 20         72 my $hier = Filesys::POSIX::Path->new($path);
84 20         42 my $dir = $self->{'cwd'};
85              
86 20         61 while ( $hier->count ) {
87 95         167 my $item = $hier->shift;
88              
89 95 100       177 unless ($item) {
90 11         15 $dir = $self->{'root'};
91 11         22 next;
92             }
93              
94 84         191 my $directory = $dir->directory;
95 84         210 my $inode = $self->{'vfs'}->vnode( $directory->get($item) );
96              
97 84 100       118 if ($inode) {
98 11         30 $dir = $inode;
99             }
100             else {
101 73         184 $dir = $dir->child( $item, $perm | $S_IFDIR );
102             }
103             }
104              
105 20         88 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 337 my ($self) = @_;
116              
117 7         19 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 663 my ( $self, $path ) = @_;
133 2         6 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 1102 my ( $self, $path ) = @_;
147              
148 4         9 my $directory = $self->stat($path)->directory;
149 4         11 $directory->open;
150              
151 4         8 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 53 my ( $self, $directory ) = @_;
163              
164 14 100       37 return $directory->read unless wantarray;
165              
166 2         1 my @ret;
167              
168 2         7 while ( defined( my $item = $directory->read ) ) {
169 10         21 push @ret, $item;
170             }
171              
172 2         7 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 27 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 2366 my ( $self, $path ) = @_;
198 27         93 my $fd = $self->open( $path, $O_CREAT );
199 27         80 my $inode = $self->fstat($fd);
200              
201 27         72 $self->close($fd);
202              
203 27         43 return $inode;
204             }
205              
206             =back
207              
208             =cut
209              
210             1;
211              
212             __END__