File Coverage

blib/lib/Filesys/POSIX/Real/Inode.pm
Criterion Covered Total %
statement 62 92 67.3
branch 21 50 42.0
condition 2 3 66.6
subroutine 14 19 73.6
pod 1 10 10.0
total 100 174 57.4


line stmt bran cond sub pod time code
1             # Copyright (c) 2016, 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 13     13   438 use strict;
  13         14  
  13         276  
11 13     13   38 use warnings;
  13         14  
  13         271  
12              
13 13     13   324 use Filesys::POSIX::Bits;
  13         9  
  13         2846  
14 13     13   378 use Filesys::POSIX::Bits::System;
  13         19  
  13         208  
15 13     13   341 use Filesys::POSIX::Inode ();
  13         18  
  13         170  
16 13     13   374 use Filesys::POSIX::Mem::Inode ();
  13         18  
  13         154  
17 13     13   58 use Filesys::POSIX::IO::Handle ();
  13         33  
  13         235  
18 13     13   38 use Filesys::POSIX::Error qw(throw);
  13         15  
  13         516  
19              
20 13     13   48 use Fcntl qw(:DEFAULT :mode);
  13         8  
  13         15250  
21              
22             our @ISA = qw(Filesys::POSIX::Inode);
23              
24             sub new {
25 46     46 0 89 my ( $class, $path, %opts ) = @_;
26              
27 46         400 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 46 50       112 if ( defined $opts{'dev'}->{'sticky'} ) {
36 0 0       0 $sticky = $opts{'dev'}->{'sticky'} ? 1 : 0;
37             }
38              
39 46 100       77 if ( defined $opts{'sticky'} ) {
40 11 100       29 $sticky = $opts{'sticky'} ? 1 : 0;
41             }
42              
43             return bless {
44             'path' => $path,
45             'dev' => $opts{'dev'},
46 46         302 'parent' => $opts{'parent'},
47             'sticky' => $sticky,
48             'dirty' => 0
49             }, $class;
50             }
51              
52             sub from_disk {
53 46     46 0 134 my ( $class, $path, %opts ) = @_;
54 46 100       434 my @st = $opts{'st_info'} ? @{ $opts{'st_info'} } : lstat $path or Carp::confess("$!");
  23 50       60  
55              
56 46         203 my $inode = $class->new( $path, %opts )->update(@st);
57              
58 46 100       178 if ( S_IFMT( $st[2] ) == S_IFDIR ) {
59 24         161 $inode->{'directory'} = Filesys::POSIX::Real::Directory->new( $path, $inode );
60             }
61              
62 46         163 return $inode;
63             }
64              
65             sub child {
66 4     4 0 5 my ( $self, $name, $mode ) = @_;
67 4         8 my $directory = $self->directory;
68              
69 4 50       11 throw &Errno::EINVAL if $name =~ /\//;
70 4 50       10 throw &Errno::EEXIST if $directory->exists($name);
71              
72 4         9 my $path = "$self->{'path'}/$name";
73              
74             my %data = (
75             'dev' => $self->{'dev'},
76 4         9 'sticky' => $self->{'sticky'},
77             'parent' => $directory->get('.')
78             );
79              
80 4 100       10 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       94 mkdir( $path, $mode ) or Carp::confess("$!");
90             }
91              
92 4         5 my $inode;
93              
94 4 50       6 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         6 my $class = ref $self;
101 4         21 $inode = $class->from_disk( $path, %data );
102             }
103              
104 4         11 return $directory->set( $name, $inode );
105             }
106              
107             sub taint {
108 0     0 0 0 my ($self) = @_;
109              
110 0         0 $self->{'dirty'} = 1;
111              
112 0         0 return $self;
113             }
114              
115             sub update {
116 53     53 1 97 my ( $self, @st ) = @_;
117              
118 53 50 66     208 if ( $self->{'sticky'} && $self->{'dirty'} ) {
119 0         0 @{$self}{qw(rdev size atime mtime ctime)} = @st[ 6 .. 10 ];
  0         0  
120             }
121             else {
122 53         205 $self->SUPER::update(@st);
123             }
124              
125 53         82 return $self;
126             }
127              
128             sub open {
129 7     7 0 11 my ( $self, $flags ) = @_;
130              
131             sysopen(
132 7 100       67 my $fh, $self->{'path'},
133             Filesys::POSIX::Bits::System::convertFlagsToSystem($flags)
134             ) or Carp::confess("$!");
135              
136 5         32 return Filesys::POSIX::IO::Handle->new($fh);
137             }
138              
139             sub chown {
140 0     0 0   my ( $self, $uid, $gid ) = @_;
141              
142 0 0         unless ( $self->{'sticky'} ) {
143 0 0         CORE::chown( $uid, $gid, $self->{'path'} ) or Carp::confess("$!");
144             }
145              
146 0           @{$self}{qw(uid gid)} = ( $uid, $gid );
  0            
147              
148 0           return $self->taint;
149             }
150              
151             sub chmod {
152 0     0 0   my ( $self, $mode ) = @_;
153 0           my $format = $self->{'mode'} & $S_IFMT;
154 0           my $perm = $mode & ( $S_IPERM | $S_IPROT );
155              
156 0 0         unless ( $self->{'sticky'} ) {
157 0 0         CORE::chmod( $perm, $self->{'path'} ) or Carp::confess("$!");
158             }
159              
160 0           $self->{'mode'} = $format | $perm;
161              
162 0           return $self->taint;
163             }
164              
165             sub readlink {
166 0     0 0   my ($self) = @_;
167              
168 0 0         unless ( $self->{'dest'} ) {
169 0 0         $self->{'dest'} = CORE::readlink( $self->{'path'} ) or Carp::confess("$!");
170             }
171              
172 0           return $self->{'dest'};
173             }
174              
175             sub symlink {
176 0     0 0   my ( $self, $dest ) = @_;
177              
178 0 0         unless ( $self->{'sticky'} ) {
179 0 0         symlink( $dest, $self->{'path'} ) or Carp::confess("$!");
180             }
181              
182 0           $self->{'dest'} = $dest;
183              
184 0           return $self->taint;
185             }
186              
187             1;