File Coverage

blib/lib/Filesys/POSIX/Extensions.pm
Criterion Covered Total %
statement 68 68 100.0
branch 10 10 100.0
condition n/a
subroutine 13 13 100.0
pod 5 5 100.0
total 96 96 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::Extensions;
9              
10 6     6   2336 use strict;
  6         7  
  6         131  
11 6     6   19 use warnings;
  6         6  
  6         103  
12              
13 6     6   38 use Filesys::POSIX::Bits;
  6         5  
  6         1363  
14 6     6   25 use Filesys::POSIX::Module ();
  6         6  
  6         66  
15 6     6   14 use Filesys::POSIX::Path ();
  6         7  
  6         59  
16 6     6   690 use Filesys::POSIX::Real::Inode ();
  6         8  
  6         67  
17 6     6   668 use Filesys::POSIX::Real::Directory ();
  6         7  
  6         94  
18              
19 6     6   19 use Filesys::POSIX::Error qw(throw);
  6         5  
  6         2503  
20              
21             my @METHODS = qw(attach map alias detach replace);
22              
23             Filesys::POSIX::Module->export_methods( __PACKAGE__, @METHODS );
24              
25             =head1 NAME
26              
27             Filesys::POSIX::Extensions - Provides features not found in a POSIX environment
28             environment
29              
30             =head1 SYNOPSIS
31              
32             use Filesys::POSIX::Extensions;
33              
34             =head1 DESCRIPTION
35              
36             This module of extensions provides system calls that would be considered
37             nonstandard in a POSIX environment, but nonetheless provide their functionality
38             with standard filesystem semantics. These extensions provide novel means of
39             performing efficient filesystem manipulation, allowing the developer to attach
40             arbitrary inodes in specified locations, detach, replace, and perform cross-
41             device symlinks.
42              
43             =head1 SYSTEM CALLS
44              
45             =over
46              
47             =item C<$fs-Eattach($inode, $dest)>
48              
49             Attaches the given inode object to the filesystem in the specified location.
50             Exceptions will be thrown for the following:
51              
52             =over
53              
54             =item * EEXIST (File exists)
55              
56             An inode at the destination path already exists.
57              
58             =back
59              
60             Upon success, the inode provided will be returned to the caller.
61              
62             =cut
63              
64             sub attach {
65 2     2 1 645 my ( $self, $inode, $dest ) = @_;
66 2         5 my $hier = Filesys::POSIX::Path->new($dest);
67 2         5 my $name = $hier->basename;
68 2         4 my $parent = $self->stat( $hier->dirname );
69 2         5 my $directory = $parent->directory;
70              
71 2         3 $! = 0;
72              
73 2 100       4 throw &Errno::EEXIST if $directory->exists($name);
74              
75 1         3 $directory->set( $name, $inode );
76              
77 1         2 return $inode;
78             }
79              
80             =item C<$fs-Emap($real_src, $dest)>
81              
82             Manifests a L object corresponding to the actual
83             inode from the underlying filesystem whose path is specified by C<$real_src>,
84             and attaches it to the virtual filesystem in the location specified by C<$dest>.
85              
86             Any inodes mapped from the real filesystem into a virtual filesystem have the
87             C update flag set, meaning, only certain operations made on the in-memory
88             inode affect the real inode. See L for further details.
89              
90             Exceptions will be thrown in the following conditions:
91              
92             =over
93              
94             =item * EEXIST (File exists)
95              
96             An inode at the destination path already exists.
97              
98             =back
99              
100             Other exceptions may be thrown, based on the availability and permissions of
101             the actual inode referred to by C<$real_src>.
102              
103             Upon success, a reference to the C object created
104             will be returned to the caller.
105              
106             =cut
107              
108             sub map {
109 8     8 1 924 my ( $self, $real_src, $dest ) = @_;
110 8         32 my $hier = Filesys::POSIX::Path->new($dest);
111 8         36 my $name = $hier->basename;
112 8         27 my $parent = $self->stat( $hier->dirname );
113 8         38 my $directory = $parent->directory;
114              
115 8         23 $! = 0;
116              
117 8 100       35 throw &Errno::EEXIST if $directory->exists($name);
118              
119             my $inode = Filesys::POSIX::Real::Inode->from_disk(
120             $real_src,
121 7         75 'dev' => $parent->{'dev'},
122             'sticky' => 1,
123             'parent' => $parent
124             );
125              
126 7         20 return $directory->set( $name, $inode );
127             }
128              
129             =item C<$fs-Ealias($src, $dest)>
130              
131             Very similar to C<$fs-Elink>, however this system call allows inode aliases
132             to be made across filesystem mount points. It is also possible to alias
133             directories, unlike C<$fs-Elink>. Exceptions will be thrown for the following:
134              
135             =over
136              
137             =item * EEXIST (File exists)
138              
139             An inode at the destination path was found.
140              
141             =back
142              
143             Upon success, a reference to the source inode will be returned to the caller.
144              
145             =cut
146              
147             sub alias {
148 4     4 1 331 my ( $self, $src, $dest ) = @_;
149 4         11 my $hier = Filesys::POSIX::Path->new($dest);
150 4         9 my $name = $hier->basename;
151 4         10 my $inode = $self->lstat($src);
152 4         10 my $parent = $self->stat( $hier->dirname );
153 4         10 my $directory = $parent->directory;
154              
155 4         6 $! = 0;
156              
157 4 100       9 throw &Errno::EEXIST if $directory->exists($name);
158              
159 3         9 return $directory->set( $name, $inode );
160             }
161              
162             =item C<$fs-Edetach($path)>
163              
164             Detaches the inode of the given path from the virtual filesystem. This call is
165             similar to C<$fs-Eunlink>, except a different underlying, filesystem-
166             dependent method is used to detach an inode from the path's parent directory in
167             the case of C<$fs-Eunlink>. Both directories and non-directories alike can
168             be detached from any point in the filesystem using this call; directories do not
169             have to be empty.
170              
171             Given a directory object, the C<$directory-Edetach> call is used, which only
172             removes the inode from the directory itself; whereas C<$directory-Edelete>,
173             as used by C<$fs-Eunlink>, would perform an L at
174             the system level in the case of a L. object.
175             This way, it is possible to only perform logical deletes of inodes, without
176             affecting the underlying filesystem when managing inodes brought into existence
177             using other system calls in this extensions module.
178              
179             Exceptions are thrown for the following:
180              
181             =over
182              
183             =item * ENOENT (No such file or directory)
184              
185             Thrown when the parent directory of the item in $path does not contain an item
186             named in the final component of the path.
187              
188             =back
189              
190             Upon success, a reference to the inode detached from the filesystem will be
191             returned.
192              
193             =cut
194              
195             sub detach {
196 3     3 1 3607 my ( $self, $path ) = @_;
197 3         11 my $hier = Filesys::POSIX::Path->new($path);
198 3         7 my $name = $hier->basename;
199 3         8 my $parent = $self->stat( $hier->dirname );
200 3         8 my $directory = $parent->directory;
201              
202 3         3 $! = 0;
203              
204 3 100       7 throw &Errno::ENOENT unless $directory->exists($name);
205              
206 2         10 return $directory->detach($name);
207             }
208              
209             =item C<$fs-Ereplace($path, $inode)>
210              
211             Replaces an existent inode specified by C<$path> with the inode object passed in
212             the C<$inode> argument. The existing and specified inodes can be of any type.
213              
214             Exceptions will be thrown for the following:
215              
216             =over
217              
218             =item * ENOENT (No such file or directory)
219              
220             No inode was found at the path specified.
221              
222             =back
223              
224             Upon success, a reference to the inode passed to this method will be returned
225             to the caller.
226              
227             =cut
228              
229             sub replace {
230 2     2 1 43 my ( $self, $path, $inode ) = @_;
231 2         7 my $hier = Filesys::POSIX::Path->new($path);
232 2         4 my $name = $hier->basename;
233 2         3 my $parent = $self->stat( $hier->dirname );
234 2         4 my $directory = $parent->directory;
235              
236 2         1 $! = 0;
237              
238 2 100       4 throw &Errno::ENOENT unless $directory->exists($name);
239              
240 1         2 $directory->detach($name);
241              
242 1         3 return $directory->set( $name, $inode );
243             }
244              
245             =back
246              
247             =cut
248              
249             1;
250              
251             __END__