File Coverage

blib/lib/Filesys/POSIX/Real/Inode.pm
Criterion Covered Total %
statement 61 91 67.0
branch 21 50 42.0
condition 2 3 66.6
subroutine 14 19 73.6
pod 1 10 10.0
total 99 173 57.2


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::Real::Inode;
9              
10 11     11   490 use strict;
  11         12  
  11         327  
11 11     11   40 use warnings;
  11         14  
  11         185  
12              
13 11     11   360 use Filesys::POSIX::Bits;
  11         12  
  11         2625  
14 11     11   388 use Filesys::POSIX::Bits::System;
  11         13  
  11         191  
15 11     11   360 use Filesys::POSIX::Inode ();
  11         12  
  11         123  
16 11     11   407 use Filesys::POSIX::Mem::Inode ();
  11         17  
  11         129  
17 11     11   62 use Filesys::POSIX::IO::Handle ();
  11         13  
  11         159  
18 11     11   36 use Filesys::POSIX::Error qw(throw);
  11         10  
  11         450  
19              
20 11     11   44 use Fcntl qw(:DEFAULT :mode);
  11         12  
  11         14595  
21              
22             our @ISA = qw(Filesys::POSIX::Inode);
23              
24             sub new {
25 37     37 0 85 my ( $class, $path, %opts ) = @_;
26              
27 37         41 my $sticky = 0;
28              
29             #
30             # Allow the sticky flag to be set for every inode belonging to a
31             # Filesys::POSIX::Real filesystem, with usage of a special mount flag.
32             # However, allow this flag to be overridden on a per-inode basis, which
33             # happens with each call from Filesys::POSIX::Extensions->map and the like.
34             #
35 37 50       112 if ( defined $opts{'dev'}->{'sticky'} ) {
36 0 0       0 $sticky = $opts{'dev'}->{'sticky'} ? 1 : 0;
37             }
38              
39 37 100       85 if ( defined $opts{'sticky'} ) {
40 11 100       32 $sticky = $opts{'sticky'} ? 1 : 0;
41             }
42              
43 37         364 return bless {
44             'path' => $path,
45             'dev' => $opts{'dev'},
46             'parent' => $opts{'parent'},
47             'sticky' => $sticky,
48             'dirty' => 0
49             }, $class;
50             }
51              
52             sub from_disk {
53 37     37 0 180 my ( $class, $path, %opts ) = @_;
54 37 100       1857 my @st = $opts{'st_info'} ? @{ $opts{'st_info'} } : lstat $path or Carp::confess("$!");
  17 50       53  
55              
56 37         219 my $inode = $class->new( $path, %opts )->update(@st);
57              
58 37 100       169 if ( S_IFMT( $st[2] ) == S_IFDIR ) {
59 18         128 $inode->{'directory'} = Filesys::POSIX::Real::Directory->new( $path, $inode );
60             }
61              
62 37         159 return $inode;
63             }
64              
65             sub child {
66 4     4 0 5 my ( $self, $name, $mode ) = @_;
67 4         11 my $directory = $self->directory;
68              
69 4 50       12 throw &Errno::EINVAL if $name =~ /\//;
70 4 50       8 throw &Errno::EEXIST if $directory->exists($name);
71              
72 4         9 my $path = "$self->{'path'}/$name";
73              
74 4         11 my %data = (
75             'dev' => $self->{'dev'},
76             'sticky' => $self->{'sticky'},
77             'parent' => $directory->get('.')
78             );
79              
80 4 100       17 if ( ( $mode & $S_IFMT ) == $S_IFREG ) {
    50          
81 2 50       11 sysopen(
82             my $fh, $path,
83             O_CREAT | O_EXCL | O_WRONLY,
84             Filesys::POSIX::Bits::System::convertModeToSystem($mode)
85             ) or Carp::confess("$!");
86 2         17 close($fh);
87             }
88             elsif ( ( $mode & $S_IFMT ) == $S_IFDIR ) {
89 2 50       111 mkdir( $path, $mode ) or Carp::confess("$!");
90             }
91              
92 4         4 my $inode;
93              
94 4 50       10 if ( ( $mode & $S_IFMT ) == $S_IFLNK ) {
95 0 0       0 throw &Errno::EPERM unless $self->{'sticky'};
96              
97 0         0 $inode = Filesys::POSIX::Mem::Inode->new( %data, 'mode' => $mode );
98             }
99             else {
100 4         22 $inode = __PACKAGE__->from_disk( $path, %data );
101             }
102              
103 4         12 return $directory->set( $name, $inode );
104             }
105              
106             sub taint {
107 0     0 0 0 my ($self) = @_;
108              
109 0         0 $self->{'dirty'} = 1;
110              
111 0         0 return $self;
112             }
113              
114             sub update {
115 39     39 1 85 my ( $self, @st ) = @_;
116              
117 39 50 66     189 if ( $self->{'sticky'} && $self->{'dirty'} ) {
118 0         0 @{$self}{qw(rdev size atime mtime ctime)} = @st[ 6 .. 10 ];
  0         0  
119             }
120             else {
121 39         228 $self->SUPER::update(@st);
122             }
123              
124 39         65 return $self;
125             }
126              
127             sub open {
128 7     7 0 12 my ( $self, $flags ) = @_;
129              
130 7 100       87 sysopen(
131             my $fh, $self->{'path'},
132             Filesys::POSIX::Bits::System::convertFlagsToSystem($flags)
133             ) or Carp::confess("$!");
134              
135 5         38 return Filesys::POSIX::IO::Handle->new($fh);
136             }
137              
138             sub chown {
139 0     0 0   my ( $self, $uid, $gid ) = @_;
140              
141 0 0         unless ( $self->{'sticky'} ) {
142 0 0         CORE::chown( $uid, $gid, $self->{'path'} ) or Carp::confess("$!");
143             }
144              
145 0           @{$self}{qw(uid gid)} = ( $uid, $gid );
  0            
146              
147 0           return $self->taint;
148             }
149              
150             sub chmod {
151 0     0 0   my ( $self, $mode ) = @_;
152 0           my $format = $self->{'mode'} & $S_IFMT;
153 0           my $perm = $mode & ( $S_IPERM | $S_IPROT );
154              
155 0 0         unless ( $self->{'sticky'} ) {
156 0 0         CORE::chmod( $perm, $self->{'path'} ) or Carp::confess("$!");
157             }
158              
159 0           $self->{'mode'} = $format | $perm;
160              
161 0           return $self->taint;
162             }
163              
164             sub readlink {
165 0     0 0   my ($self) = @_;
166              
167 0 0         unless ( $self->{'dest'} ) {
168 0 0         $self->{'dest'} = CORE::readlink( $self->{'path'} ) or Carp::confess("$!");
169             }
170              
171 0           return $self->{'dest'};
172             }
173              
174             sub symlink {
175 0     0 0   my ( $self, $dest ) = @_;
176              
177 0 0         unless ( $self->{'sticky'} ) {
178 0 0         symlink( $dest, $self->{'path'} ) or Carp::confess("$!");
179             }
180              
181 0           $self->{'dest'} = $dest;
182              
183 0           return $self->taint;
184             }
185              
186             1;