File Coverage

blib/lib/Filesys/POSIX/IO.pm
Criterion Covered Total %
statement 67 67 100.0
branch 22 22 100.0
condition n/a
subroutine 16 16 100.0
pod 9 9 100.0
total 114 114 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::IO;
9              
10 25     25   79 use strict;
  25         25  
  25         524  
11 25     25   75 use warnings;
  25         26  
  25         436  
12              
13 25     25   72 use Filesys::POSIX::Bits;
  25         21  
  25         5275  
14 25     25   8378 use Filesys::POSIX::Module ();
  25         39  
  25         326  
15 25     25   85 use Filesys::POSIX::FdTable ();
  25         22  
  25         236  
16 25     25   68 use Filesys::POSIX::Path ();
  25         27  
  25         313  
17 25     25   67 use Filesys::POSIX::Error qw(throw);
  25         24  
  25         15415  
18              
19             my @MODULES = qw(open read write print printf tell seek close fdopen);
20              
21             Filesys::POSIX::Module->export_methods( __PACKAGE__, @MODULES );
22              
23             =head1 NAME
24              
25             Filesys::POSIX::IO - Provides file I/O calls for L
26              
27             =head1 DESCRIPTION
28              
29             C is a mixin imported into the Filesys::POSIX namespace by
30             the L module itself. This module provides the standard file I/O
31             routines.
32              
33             =over
34              
35             =item C<$fs-Eopen($path, $flags)>
36              
37             =item C<$fs-Eopen($path, $flags, $mode)>
38              
39             Open a file descriptor for an inode specified by $path. This operation can be
40             modified by usage of the following flags which can be specified together using
41             logical OR (|). The flags as follows are exported by L:
42              
43             =over
44              
45             =item C<$O_CREAT>
46              
47             If an inode at the specified path does not exist, attempt to create one.
48              
49             When a mode is specified, the value is split into the format (C<$S_IFMT>),
50             permission (C<$S_IPERM>), and protection (C<$S_IPROT>) bitfields. If no
51             value was specified for the format, then the default value of C<$S_IFREG>
52             (regular file) is substituted.
53              
54             When no mode is specified whatsoever, the default values of an C<$S_IFREG>
55             format, and a mode of 0666 are used, modified by the current umask value.
56              
57             In either case, the permissions to be used are modified with an exclusive OR
58             operation by the current umask value.
59              
60             =item C<$O_EXCL>
61              
62             When specified in the presence of C<$O_CREAT>, the call will only succeed when
63             the path lists a nonexisting inode. A "File exists" exception will be thrown if
64             this is not the case.
65              
66             =item C<$O_TRUNC>
67              
68             When specified, any existing file data will be truncated, and the file handle
69             position will start at offset 0 (zero).
70              
71             =item C<$O_APPEND>
72              
73             When specified, the file handle position will start at the offset value equal
74             to the size of the file.
75              
76             =item C<$O_RDONLY>
77              
78             The default flag field value. When neither C<$O_WRONLY> nor C<$O_RDWR> are
79             specified, any write operations will be prohibited on the newly issued file
80             descriptor.
81              
82             =item C<$O_WRONLY>
83              
84             When specified, any read operations will be prohibited on the newly issued file
85             descriptor.
86              
87             =item C<$O_RDWR>
88              
89             When specified, both read and write operations will be allowed on the newly
90             issued file descriptor.
91              
92             =back
93              
94             The following exceptions may be thrown.
95              
96             =over
97              
98             =item * EINVAL (Invalid argument)
99              
100             No flags were specified in I<$flags>.
101              
102             =item * EEXIST (File exists)
103              
104             When the C<$O_CREAT> flag is passed, this error may occur if a file located at
105             I<$path> already exists.
106              
107             =back
108              
109             =cut
110              
111             sub open {
112 78     78 1 6854 my ( $self, $path, $flags, $mode ) = @_;
113 78         186 my $hier = Filesys::POSIX::Path->new($path);
114 78         161 my $name = $hier->basename;
115 78         66 my $inode;
116              
117 78 100       121 throw &Errno::EINVAL unless defined $flags;
118              
119 77 100       134 if ( $flags & $O_CREAT ) {
120 72         143 my $parent = $self->stat( $hier->dirname );
121 72         126 my $directory = $parent->directory;
122              
123 71 100       136 if ( $inode = $directory->get($name) ) {
124 7 100       15 throw &Errno::EEXIST if $flags & $O_EXCL;
125             }
126             else {
127 64 100       100 my $format =
    100          
128             $mode
129             ? ( $mode & $S_IFMT ? $mode & $S_IFMT : $S_IFREG )
130             : $S_IFREG;
131 64 100       90 my $perms = $mode ? $mode & ( $S_IPERM | $S_IPROT ) : $S_IRW;
132              
133 64         79 $perms &= ~$self->{'umask'};
134              
135 64         158 $inode = $parent->child( $name, $format | $perms );
136             }
137             }
138             else {
139 5         9 $inode = $self->stat($path);
140             }
141              
142 75         182 return $self->{'fds'}->open( $inode, $flags );
143             }
144              
145             =item C<$fs-Eread($fd, $buf, $len)>
146              
147             Perform a read on the file descriptor passed, storing at maximum the number of
148             bytes specified in C<$len>, into C<$buf>. Returns the number of bytes actually
149             read; fewer bytes may be read than requested if the expected amount of data from
150             the current file handle position, plus the requested length, does not
151             match the requested length, such as when the length exceeds the end of the file
152             stream. Returns zero if no more data is available to be read.
153              
154             Exceptions are thrown for the following:
155              
156             =over
157              
158             =item * EINVAL (Invalid argument)
159              
160             A read was attempted on a write-only file descriptor.
161              
162             =back
163              
164             =cut
165              
166             sub read {
167 5     5 1 180 my $self = shift;
168 5         10 my $fd = shift;
169 5         14 my $entry = $self->{'fds'}->lookup($fd);
170              
171 4 100       14 throw &Errno::EBADF if $entry->{'flags'} & $O_WRONLY;
172              
173 3         9 return $entry->{'handle'}->read(@_);
174             }
175              
176             =item C<$fs-Ewrite($fd, $buf, $len)>
177              
178             Perform a write on the file descriptor passed, writing at maximum the number of
179             bytes specified in C<$len> from C<$buf> to the open file. Returns the number of
180             bytes actually written; fewer bytes may be written than requested if the buffer
181             does not contain enough, or if the underlying file handle implementation was
182             not able to write the full amount in the case of a L
183             object issued for an open L object.
184              
185             The following exceptions may be thrown:
186              
187             =over
188              
189             =item * EINVAL (Invalid argument)
190              
191             A write was attempted on a read-only file descriptor.
192              
193             =back
194              
195             =cut
196              
197             sub write {
198 524     524 1 972 my ( $self, $fd, $buf, $len ) = @_;
199 524         666 my $entry = $self->{'fds'}->lookup($fd);
200              
201 524 100       612 throw &Errno::EINVAL unless $entry->{'flags'} & ( $O_WRONLY | $O_RDWR );
202              
203 523         724 return $entry->{'handle'}->write( $buf, $len );
204             }
205              
206             =item C<$fs-Eprint($fd, @args)>
207              
208             Works similarly to C<$fs-Ewrite>. Each argument is concatenated using the
209             current value of C<$/> (see L), and passed with the amalgamated value's
210             length to the underlying file handle's C<$handle-Ewrite> call.
211              
212             Exceptions may be thrown for the following:
213              
214             =over
215              
216             =item * EINVAL (Invalid argument)
217              
218             Issued when called on a read-only file descriptor.
219              
220             =back
221              
222             =cut
223              
224             sub print {
225 9     9 1 31 my ( $self, $fd, @args ) = @_;
226 9         21 my $entry = $self->{'fds'}->lookup($fd);
227              
228 9 100       23 throw &Errno::EINVAL unless $entry->{'flags'} & ( $O_WRONLY | $O_RDWR );
229              
230 8         21 my $buf = join( $/, @args );
231              
232 8         23 return $entry->{'handle'}->write( $buf, length $buf );
233             }
234              
235             =item C<$fs-Eprintf($fd, $format, @args)>
236              
237             Similar to C<$fs-Eprint>, this call allows writes formatted by
238             L to be made to the given file descriptor.
239              
240             Exceptions are thrown for:
241              
242             =over
243              
244             =item * EINVAL (Invalid argument)
245              
246             Issued when called on a read-only file descriptor.
247              
248             =back
249              
250             =cut
251              
252             sub printf {
253 2     2 1 7 my ( $self, $fd, $format, @args ) = @_;
254 2         5 my $entry = $self->{'fds'}->lookup($fd);
255              
256 2 100       9 throw &Errno::EINVAL unless $entry->{'flags'} & ( $O_WRONLY | $O_RDWR );
257              
258 1         3 my $buf = sprintf( $format, @args );
259              
260 1         3 return $entry->{'handle'}->write( $buf, length $buf );
261             }
262              
263             =item C<$fs-Etell($fd)>
264              
265             Returns the byte offset of the file descriptor's file handle.
266              
267             =cut
268              
269             sub tell {
270 4     4 1 8 my ( $self, $fd ) = @_;
271 4         8 my $entry = $self->{'fds'}->lookup($fd);
272              
273 4         10 return $entry->{'handle'}->tell;
274             }
275              
276             =item C<$fs-Eseek($fd, $pos, $whence)>
277              
278             Sets the byte offset of the file descriptor's file handle, relative to the
279             current offset as modified by the value specified in $whence. $whence can be
280             used to specify how the new position will be set relative to the current offset
281             with the following values (in L):
282              
283             =over
284              
285             =item C<$SEEK_SET>
286              
287             The new offset of the file handle will be set to C<0 + $pos> bytes, or, relative
288             to the beginning of the file. This sets the file handle to an absolute offset.
289              
290             =item C<$SEEK_CUR>
291              
292             The new offset of the file handle will be set to C<$cur + $pos> bytes, or,
293             relative to the current file handle offset.
294              
295             =item C<$SEEK_END>
296              
297             The new offset of the file will be set to C<$size + $pos> bytes, or, relative to
298             the end of the file.
299              
300             =back
301              
302             =cut
303              
304             sub seek {
305 4     4 1 6 my ( $self, $fd, $pos, $whence ) = @_;
306 4         11 my $entry = $self->{'fds'}->lookup($fd);
307              
308 4         11 return $entry->{'handle'}->seek( $pos, $whence );
309             }
310              
311             =item C<$fs-Eclose($fd)>
312              
313             Close the file handle issued for the given file descriptor, and deallocate said
314             file descriptor. The file descriptor will then be freed for subsequent use and
315             issue by C<$fs-Eopen>.
316              
317             =cut
318              
319             sub close {
320 66     66 1 2340 my ( $self, $fd ) = @_;
321 66         141 $self->{'fds'}->close($fd);
322             }
323              
324             =item C<$fs-Efdopen($fd)>
325              
326             Returns the underlying file handle opened for the file descriptor passed.
327              
328             =cut
329              
330             sub fdopen {
331 1     1 1 5 my ( $self, $fd ) = @_;
332 1         2 my $entry = $self->{'fds'}->lookup($fd);
333              
334 1         3 return $entry->{'handle'};
335             }
336              
337             =back
338              
339             =cut
340              
341             1;
342              
343             __END__