line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
## <https://perl.apache.org/docs/2.0/api/APR/Finfo.html> |
2
|
|
|
|
|
|
|
##---------------------------------------------------------------------------- |
3
|
|
|
|
|
|
|
## Apache2 Server Side Include Parser - ~/lib/Apache2/SSI/Finfo.pm |
4
|
|
|
|
|
|
|
## Version v0.1.1 |
5
|
|
|
|
|
|
|
## Copyright(c) 2021 DEGUEST Pte. Ltd. |
6
|
|
|
|
|
|
|
## Author: Jacques Deguest <jack@deguest.jp> |
7
|
|
|
|
|
|
|
## Created 2020/12/18 |
8
|
|
|
|
|
|
|
## Modified 2021/03/29 |
9
|
|
|
|
|
|
|
## All rights reserved |
10
|
|
|
|
|
|
|
## |
11
|
|
|
|
|
|
|
## This program is free software; you can redistribute it and/or modify it |
12
|
|
|
|
|
|
|
## under the same terms as Perl itself. |
13
|
|
|
|
|
|
|
##---------------------------------------------------------------------------- |
14
|
|
|
|
|
|
|
package Apache2::SSI::Finfo; |
15
|
|
|
|
|
|
|
BEGIN |
16
|
|
|
|
|
|
|
{ |
17
|
17
|
|
|
17
|
|
85299
|
use strict; |
|
17
|
|
|
|
|
38
|
|
|
17
|
|
|
|
|
573
|
|
18
|
17
|
|
|
17
|
|
81
|
use warnings; |
|
17
|
|
|
|
|
30
|
|
|
17
|
|
|
|
|
488
|
|
19
|
17
|
|
|
17
|
|
84
|
use warnings::register; |
|
17
|
|
|
|
|
25
|
|
|
17
|
|
|
|
|
2405
|
|
20
|
17
|
|
|
17
|
|
475
|
use parent qw( Module::Generic ); |
|
17
|
|
|
|
|
266
|
|
|
17
|
|
|
|
|
113
|
|
21
|
17
|
|
|
17
|
|
11146224
|
use Apache2::SSI::File::Type; |
|
17
|
|
|
|
|
63
|
|
|
17
|
|
|
|
|
408
|
|
22
|
17
|
|
|
17
|
|
7616
|
use Exporter qw( import ); |
|
17
|
|
|
|
|
62
|
|
|
17
|
|
|
|
|
607
|
|
23
|
17
|
|
|
17
|
|
105
|
use DateTime; |
|
17
|
|
|
|
|
32
|
|
|
17
|
|
|
|
|
416
|
|
24
|
17
|
|
|
17
|
|
88
|
use DateTime::Format::Strptime; |
|
17
|
|
|
|
|
28
|
|
|
17
|
|
|
|
|
234
|
|
25
|
17
|
|
|
17
|
|
899
|
use File::Basename (); |
|
17
|
|
|
|
|
32
|
|
|
17
|
|
|
|
|
286
|
|
26
|
17
|
|
|
17
|
|
77
|
use Nice::Try; |
|
17
|
|
|
|
|
29
|
|
|
17
|
|
|
|
|
240
|
|
27
|
17
|
|
|
17
|
|
46
|
our( $AUTOLOAD ); |
28
|
|
|
|
|
|
|
use overload ( |
29
|
25
|
|
|
25
|
|
292
|
q{""} => sub { $_[0]->{filepath} }, |
30
|
|
|
|
|
|
|
bool => sub () { 1 }, |
31
|
17
|
|
|
|
|
292
|
fallback => 1, |
32
|
17
|
|
|
17
|
|
13435101
|
); |
|
17
|
|
|
|
|
44
|
|
33
|
17
|
50
|
|
|
|
194
|
if( exists( $ENV{MOD_PERL} ) ) |
34
|
|
|
|
|
|
|
{ |
35
|
0
|
|
|
|
|
0
|
require APR::Pool; |
36
|
0
|
|
|
|
|
0
|
require APR::Finfo; |
37
|
0
|
|
|
|
|
0
|
require APR::Const; |
38
|
0
|
|
|
|
|
0
|
APR::Const->import( -compile => qw( :filetype FINFO_NORM ) ); |
39
|
|
|
|
|
|
|
} |
40
|
17
|
|
|
17
|
|
2872
|
use constant FINFO_DEV => 0; |
|
17
|
|
|
|
|
38
|
|
|
17
|
|
|
|
|
1503
|
|
41
|
17
|
|
|
17
|
|
99
|
use constant FINFO_INODE => 1; |
|
17
|
|
|
|
|
31
|
|
|
17
|
|
|
|
|
732
|
|
42
|
17
|
|
|
17
|
|
101
|
use constant FINFO_MODE => 2; |
|
17
|
|
|
|
|
32
|
|
|
17
|
|
|
|
|
674
|
|
43
|
17
|
|
|
17
|
|
92
|
use constant FINFO_NLINK => 3; |
|
17
|
|
|
|
|
29
|
|
|
17
|
|
|
|
|
663
|
|
44
|
17
|
|
|
17
|
|
90
|
use constant FINFO_UID => 4; |
|
17
|
|
|
|
|
34
|
|
|
17
|
|
|
|
|
700
|
|
45
|
17
|
|
|
17
|
|
89
|
use constant FINFO_GID => 5; |
|
17
|
|
|
|
|
33
|
|
|
17
|
|
|
|
|
767
|
|
46
|
17
|
|
|
17
|
|
93
|
use constant FINFO_RDEV => 6; |
|
17
|
|
|
|
|
30
|
|
|
17
|
|
|
|
|
706
|
|
47
|
17
|
|
|
17
|
|
88
|
use constant FINFO_SIZE => 7; |
|
17
|
|
|
|
|
34
|
|
|
17
|
|
|
|
|
642
|
|
48
|
17
|
|
|
17
|
|
87
|
use constant FINFO_ATIME => 8; |
|
17
|
|
|
|
|
27
|
|
|
17
|
|
|
|
|
629
|
|
49
|
17
|
|
|
17
|
|
85
|
use constant FINFO_MTIME => 9; |
|
17
|
|
|
|
|
356
|
|
|
17
|
|
|
|
|
673
|
|
50
|
17
|
|
|
17
|
|
93
|
use constant FINFO_CTIME => 10; |
|
17
|
|
|
|
|
24
|
|
|
17
|
|
|
|
|
638
|
|
51
|
17
|
|
|
17
|
|
85
|
use constant FINFO_BLOCK_SIZE => 11; |
|
17
|
|
|
|
|
27
|
|
|
17
|
|
|
|
|
720
|
|
52
|
17
|
|
|
17
|
|
86
|
use constant FINFO_BLOCKS => 12; |
|
17
|
|
|
|
|
28
|
|
|
17
|
|
|
|
|
851
|
|
53
|
|
|
|
|
|
|
## Sames constant value as in APR::Const |
54
|
|
|
|
|
|
|
## the file type is undetermined. |
55
|
17
|
|
|
17
|
|
93
|
use constant FILETYPE_NOFILE => 0; |
|
17
|
|
|
|
|
30
|
|
|
17
|
|
|
|
|
702
|
|
56
|
|
|
|
|
|
|
## a file is a regular file. |
57
|
17
|
|
|
17
|
|
86
|
use constant FILETYPE_REG => 1; |
|
17
|
|
|
|
|
24
|
|
|
17
|
|
|
|
|
661
|
|
58
|
|
|
|
|
|
|
## a file is a directory |
59
|
17
|
|
|
17
|
|
84
|
use constant FILETYPE_DIR => 2; |
|
17
|
|
|
|
|
28
|
|
|
17
|
|
|
|
|
641
|
|
60
|
|
|
|
|
|
|
## a file is a character device |
61
|
17
|
|
|
17
|
|
79
|
use constant FILETYPE_CHR => 3; |
|
17
|
|
|
|
|
27
|
|
|
17
|
|
|
|
|
758
|
|
62
|
|
|
|
|
|
|
## a file is a block device |
63
|
17
|
|
|
17
|
|
82
|
use constant FILETYPE_BLK => 4; |
|
17
|
|
|
|
|
32
|
|
|
17
|
|
|
|
|
730
|
|
64
|
|
|
|
|
|
|
## a file is a FIFO or a pipe. |
65
|
17
|
|
|
17
|
|
153
|
use constant FILETYPE_PIPE => 5; |
|
17
|
|
|
|
|
30
|
|
|
17
|
|
|
|
|
661
|
|
66
|
|
|
|
|
|
|
## a file is a symbolic link |
67
|
17
|
|
|
17
|
|
82
|
use constant FILETYPE_LNK => 6; |
|
17
|
|
|
|
|
25
|
|
|
17
|
|
|
|
|
646
|
|
68
|
|
|
|
|
|
|
## a file is a [unix domain] socket. |
69
|
17
|
|
|
17
|
|
111
|
use constant FILETYPE_SOCK => 7; |
|
17
|
|
|
|
|
30
|
|
|
17
|
|
|
|
|
627
|
|
70
|
|
|
|
|
|
|
## a file is of some other unknown type or the type cannot be determined. |
71
|
17
|
|
|
17
|
|
86
|
use constant FILETYPE_UNKFILE => 127; |
|
17
|
|
|
|
|
71
|
|
|
17
|
|
|
|
|
1923
|
|
72
|
17
|
|
|
|
|
83
|
our %EXPORT_TAGS = ( all => [qw( FILETYPE_NOFILE FILETYPE_REG FILETYPE_DIR FILETYPE_CHR FILETYPE_BLK FILETYPE_PIPE FILETYPE_LNK FILETYPE_SOCK FILETYPE_UNKFILE )] ); |
73
|
17
|
|
|
|
|
53
|
our @EXPORT_OK = qw( FILETYPE_NOFILE FILETYPE_REG FILETYPE_DIR FILETYPE_CHR FILETYPE_BLK FILETYPE_PIPE FILETYPE_LNK FILETYPE_SOCK FILETYPE_UNKFILE ); |
74
|
17
|
|
|
|
|
39708
|
our $VERSION = 'v0.1.1'; |
75
|
|
|
|
|
|
|
}; |
76
|
|
|
|
|
|
|
|
77
|
|
|
|
|
|
|
sub init |
78
|
|
|
|
|
|
|
{ |
79
|
160
|
|
|
160
|
1
|
7926
|
my $self = shift( @_ ); |
80
|
160
|
|
50
|
|
|
530
|
my $file = shift( @_ ) || return( $self->error( "No file provided to instantiate a ", ref( $self ), " object." ) ); |
81
|
|
|
|
|
|
|
## return( $self->error( "File or directory \"$file\" does not exist." ) ) if( !-e( $file ) ); |
82
|
160
|
|
|
|
|
1414
|
$self->{apache_request} = ''; |
83
|
160
|
|
|
|
|
409
|
$self->{apr_finfo} = ''; |
84
|
160
|
|
|
|
|
382
|
$self->{_init_strict_use_sub} = 1; |
85
|
160
|
|
|
|
|
1145
|
$self->SUPER::init( @_ ); |
86
|
160
|
|
|
|
|
15081
|
$self->{filepath} = $file; |
87
|
160
|
|
|
|
|
626
|
$self->{_data} = []; |
88
|
160
|
|
|
|
|
344
|
my $r = $self->{apache_request}; |
89
|
160
|
50
|
|
|
|
399
|
if( $r ) |
90
|
|
|
|
|
|
|
{ |
91
|
|
|
|
|
|
|
## <https://perl.apache.org/docs/2.0/api/Apache2/RequestRec.html#toc_C_filename_> |
92
|
0
|
|
|
|
|
0
|
try |
93
|
0
|
|
|
0
|
|
0
|
{ |
94
|
0
|
|
|
|
|
0
|
my $finfo; |
95
|
0
|
0
|
|
|
|
0
|
if( $r->filename eq $file ) |
96
|
|
|
|
|
|
|
{ |
97
|
0
|
|
|
|
|
0
|
$finfo = $r->finfo; |
98
|
|
|
|
|
|
|
} |
99
|
|
|
|
|
|
|
else |
100
|
|
|
|
|
|
|
{ |
101
|
0
|
|
|
|
|
0
|
$finfo = APR::Finfo::stat( $file, APR::Const::FINFO_NORM, $r->pool ); |
102
|
0
|
|
|
|
|
0
|
$r->finfo( $finfo ); |
103
|
|
|
|
|
|
|
} |
104
|
0
|
|
|
|
|
0
|
$self->{apr_finfo} = $finfo; |
105
|
|
|
|
|
|
|
} |
106
|
0
|
0
|
|
|
|
0
|
catch( $e ) |
|
0
|
0
|
|
|
|
0
|
|
|
0
|
0
|
|
|
|
0
|
|
|
0
|
0
|
|
|
|
0
|
|
|
0
|
0
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
107
|
0
|
|
|
0
|
|
0
|
{ |
108
|
|
|
|
|
|
|
## This makes it possible to query this api even if provided with a non-existing file |
109
|
0
|
0
|
|
|
|
0
|
if( $e =~ /No[[:blank:]\h]+such[[:blank:]\h]+file[[:blank:]\h]+or[[:blank:]\h]+directory/i ) |
110
|
|
|
|
|
|
|
{ |
111
|
0
|
|
|
|
|
0
|
$self->{_data} = []; |
112
|
|
|
|
|
|
|
} |
113
|
|
|
|
|
|
|
else |
114
|
|
|
|
|
|
|
{ |
115
|
0
|
|
|
|
|
0
|
return( $self->error( "Unable to set the APR::Finfo object: $e" ) ); |
116
|
|
|
|
|
|
|
} |
117
|
0
|
0
|
0
|
|
|
0
|
} |
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
|
|
|
0
|
|
|
0
|
0
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
118
|
|
|
|
|
|
|
} |
119
|
|
|
|
|
|
|
else |
120
|
|
|
|
|
|
|
{ |
121
|
160
|
|
|
|
|
3865
|
$self->{_data} = [CORE::stat( $file )]; |
122
|
|
|
|
|
|
|
} |
123
|
160
|
|
|
|
|
962
|
return( $self ); |
124
|
|
|
|
|
|
|
} |
125
|
|
|
|
|
|
|
|
126
|
5
|
|
|
5
|
1
|
38
|
sub apache_request { return( shift->_set_get_object_without_init( 'apache_request', 'Apache2::RequestRec', @_ ) ); } |
127
|
|
|
|
|
|
|
|
128
|
49
|
|
|
49
|
1
|
317
|
sub apr_finfo { return( shift->_set_get_object( 'apr_finfo', 'APR::Finfo', @_ ) ); } |
129
|
|
|
|
|
|
|
|
130
|
|
|
|
|
|
|
sub atime |
131
|
|
|
|
|
|
|
{ |
132
|
1
|
|
|
1
|
1
|
3
|
my $self = shift( @_ ); |
133
|
1
|
|
|
|
|
3
|
my $f = $self->apr_finfo; |
134
|
1
|
|
|
|
|
71
|
my $t; |
135
|
1
|
50
|
|
|
|
4
|
if( $f ) |
136
|
|
|
|
|
|
|
{ |
137
|
0
|
|
|
|
|
0
|
$t = $f->atime; |
138
|
|
|
|
|
|
|
} |
139
|
|
|
|
|
|
|
else |
140
|
|
|
|
|
|
|
{ |
141
|
1
|
|
|
|
|
3
|
my $data = $self->{_data}; |
142
|
1
|
50
|
|
|
|
4
|
return( '' ) if( !scalar( @$data ) ); |
143
|
1
|
|
|
|
|
3
|
$t = $data->[ FINFO_ATIME ]; |
144
|
|
|
|
|
|
|
} |
145
|
1
|
|
|
|
|
5
|
return( $self->_datetime( $t ) ); |
146
|
|
|
|
|
|
|
} |
147
|
|
|
|
|
|
|
|
148
|
0
|
|
|
0
|
1
|
0
|
sub blksize { return( shift->block_size( @_ ) ); } |
149
|
|
|
|
|
|
|
|
150
|
|
|
|
|
|
|
sub block_size |
151
|
|
|
|
|
|
|
{ |
152
|
0
|
|
|
0
|
0
|
0
|
my $self = shift( @_ ); |
153
|
0
|
|
|
|
|
0
|
my $f = $self->apr_finfo; |
154
|
0
|
0
|
|
|
|
0
|
if( $f ) |
155
|
|
|
|
|
|
|
{ |
156
|
0
|
|
|
|
|
0
|
return( ( CORE::stat( $self->{filepath} ) )[ FINFO_BLOCK_SIZE ] ); |
157
|
|
|
|
|
|
|
} |
158
|
|
|
|
|
|
|
else |
159
|
|
|
|
|
|
|
{ |
160
|
0
|
|
|
|
|
0
|
my $data = $self->{_data}; |
161
|
0
|
0
|
|
|
|
0
|
return( '' ) if( !scalar( @$data ) ); |
162
|
0
|
|
|
|
|
0
|
return( $data->[ FINFO_BLOCK_SIZE ] ); |
163
|
|
|
|
|
|
|
} |
164
|
|
|
|
|
|
|
} |
165
|
|
|
|
|
|
|
|
166
|
|
|
|
|
|
|
sub blocks |
167
|
|
|
|
|
|
|
{ |
168
|
0
|
|
|
0
|
1
|
0
|
my $self = shift( @_ ); |
169
|
0
|
|
|
|
|
0
|
my $f = $self->apr_finfo; |
170
|
0
|
0
|
|
|
|
0
|
if( $f ) |
171
|
|
|
|
|
|
|
{ |
172
|
0
|
|
|
|
|
0
|
return( ( CORE::stat( $self->{filepath} ) )[ FINFO_BLOCKS ] ); |
173
|
|
|
|
|
|
|
} |
174
|
|
|
|
|
|
|
else |
175
|
|
|
|
|
|
|
{ |
176
|
0
|
|
|
|
|
0
|
my $data = $self->{_data}; |
177
|
0
|
0
|
|
|
|
0
|
return( '' ) if( !scalar( @$data ) ); |
178
|
0
|
|
|
|
|
0
|
return( $data->[ FINFO_BLOCKS ] ); |
179
|
|
|
|
|
|
|
} |
180
|
|
|
|
|
|
|
} |
181
|
|
|
|
|
|
|
|
182
|
1
|
|
|
1
|
1
|
6
|
sub can_read { return( -r( shift->filepath ) ); } |
183
|
|
|
|
|
|
|
|
184
|
1
|
|
|
1
|
1
|
13
|
sub can_write { return( -w( shift->filepath ) ); } |
185
|
|
|
|
|
|
|
|
186
|
1
|
|
|
1
|
1
|
4
|
sub can_exec { return( -x( shift->filepath ) ); } |
187
|
|
|
|
|
|
|
|
188
|
1
|
|
|
1
|
1
|
384
|
sub can_execute { return( -x( shift->filepath ) ); } |
189
|
|
|
|
|
|
|
|
190
|
1
|
|
|
1
|
1
|
4
|
sub csize { return( shift->size ); } |
191
|
|
|
|
|
|
|
|
192
|
|
|
|
|
|
|
sub ctime |
193
|
|
|
|
|
|
|
{ |
194
|
1
|
|
|
1
|
1
|
2
|
my $self = shift( @_ ); |
195
|
1
|
|
|
|
|
4
|
my $f = $self->apr_finfo; |
196
|
1
|
|
|
|
|
65
|
my $t; |
197
|
1
|
50
|
|
|
|
3
|
if( $f ) |
198
|
|
|
|
|
|
|
{ |
199
|
0
|
|
|
|
|
0
|
$t = $f->ctime; |
200
|
|
|
|
|
|
|
} |
201
|
|
|
|
|
|
|
else |
202
|
|
|
|
|
|
|
{ |
203
|
1
|
|
|
|
|
2
|
my $data = $self->{_data}; |
204
|
1
|
50
|
|
|
|
3
|
return( '' ) if( !scalar( @$data ) ); |
205
|
1
|
|
|
|
|
2
|
$t = $data->[ FINFO_CTIME ]; |
206
|
|
|
|
|
|
|
} |
207
|
1
|
|
|
|
|
4
|
return( $self->_datetime( $t ) ); |
208
|
|
|
|
|
|
|
} |
209
|
|
|
|
|
|
|
|
210
|
0
|
|
|
0
|
1
|
0
|
sub dev { return( shift->device( @_ ) ); } |
211
|
|
|
|
|
|
|
|
212
|
|
|
|
|
|
|
sub device |
213
|
|
|
|
|
|
|
{ |
214
|
1
|
|
|
1
|
1
|
3
|
my $self = shift( @_ ); |
215
|
1
|
|
|
|
|
3
|
my $f = $self->apr_finfo; |
216
|
1
|
50
|
|
|
|
85
|
if( $f ) |
217
|
|
|
|
|
|
|
{ |
218
|
0
|
|
|
|
|
0
|
return( $f->device ); |
219
|
|
|
|
|
|
|
} |
220
|
|
|
|
|
|
|
else |
221
|
|
|
|
|
|
|
{ |
222
|
1
|
|
|
|
|
4
|
my $data = $self->{_data}; |
223
|
1
|
50
|
|
|
|
4
|
return( '' ) if( !scalar( @$data ) ); |
224
|
1
|
|
|
|
|
6
|
return( $data->[ FINFO_DEV ] ); |
225
|
|
|
|
|
|
|
} |
226
|
|
|
|
|
|
|
} |
227
|
|
|
|
|
|
|
|
228
|
10
|
100
|
|
10
|
1
|
82
|
sub exists { return( shift->filetype == FILETYPE_NOFILE ? 0 : 1 ); } |
229
|
|
|
|
|
|
|
|
230
|
|
|
|
|
|
|
## Read-only |
231
|
6
|
|
|
6
|
1
|
34
|
sub filepath { return( shift->_set_get_scalar( 'filepath' ) ); } |
232
|
|
|
|
|
|
|
|
233
|
|
|
|
|
|
|
sub filetype |
234
|
|
|
|
|
|
|
{ |
235
|
23
|
|
|
23
|
1
|
557
|
my $self = shift( @_ ); |
236
|
23
|
|
|
|
|
98
|
my $f = $self->apr_finfo; |
237
|
23
|
50
|
|
|
|
2460
|
if( $f ) |
238
|
|
|
|
|
|
|
{ |
239
|
0
|
|
|
|
|
0
|
return( $f->filetype ); |
240
|
|
|
|
|
|
|
} |
241
|
|
|
|
|
|
|
else |
242
|
|
|
|
|
|
|
{ |
243
|
23
|
|
|
|
|
69
|
my $file = $self->{filepath}; |
244
|
23
|
|
|
|
|
193
|
$self->message( 3, "Stating file '$file'" ); |
245
|
23
|
|
|
|
|
744
|
CORE::stat( $file ); |
246
|
23
|
100
|
|
|
|
202
|
if( !-e( _ ) ) |
|
|
100
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
247
|
|
|
|
|
|
|
{ |
248
|
4
|
|
|
|
|
43
|
return( FILETYPE_NOFILE ); |
249
|
|
|
|
|
|
|
} |
250
|
|
|
|
|
|
|
elsif( -f( _ ) ) |
251
|
|
|
|
|
|
|
{ |
252
|
17
|
|
|
|
|
154
|
return( FILETYPE_REG ); |
253
|
|
|
|
|
|
|
} |
254
|
|
|
|
|
|
|
elsif( -d( _ ) ) |
255
|
|
|
|
|
|
|
{ |
256
|
2
|
|
|
|
|
25
|
return( FILETYPE_DIR ); |
257
|
|
|
|
|
|
|
} |
258
|
|
|
|
|
|
|
elsif( -l( _ ) ) |
259
|
|
|
|
|
|
|
{ |
260
|
0
|
|
|
|
|
0
|
return( FILETYPE_LNK ); |
261
|
|
|
|
|
|
|
} |
262
|
|
|
|
|
|
|
elsif( -p( _ ) ) |
263
|
|
|
|
|
|
|
{ |
264
|
0
|
|
|
|
|
0
|
return( FILETYPE_PIPE ); |
265
|
|
|
|
|
|
|
} |
266
|
|
|
|
|
|
|
elsif( -S( _ ) ) |
267
|
|
|
|
|
|
|
{ |
268
|
0
|
|
|
|
|
0
|
return( FILETYPE_SOCK ); |
269
|
|
|
|
|
|
|
} |
270
|
|
|
|
|
|
|
elsif( -b( _ ) ) |
271
|
|
|
|
|
|
|
{ |
272
|
0
|
|
|
|
|
0
|
return( FILETYPE_BLK ); |
273
|
|
|
|
|
|
|
} |
274
|
|
|
|
|
|
|
elsif( -c( _ ) ) |
275
|
|
|
|
|
|
|
{ |
276
|
0
|
|
|
|
|
0
|
return( FILETYPE_CHR ); |
277
|
|
|
|
|
|
|
} |
278
|
|
|
|
|
|
|
else |
279
|
|
|
|
|
|
|
{ |
280
|
0
|
|
|
|
|
0
|
return( FILETYPE_UNKFILE ); |
281
|
|
|
|
|
|
|
} |
282
|
|
|
|
|
|
|
} |
283
|
|
|
|
|
|
|
} |
284
|
|
|
|
|
|
|
|
285
|
|
|
|
|
|
|
sub fname |
286
|
|
|
|
|
|
|
{ |
287
|
4
|
|
|
4
|
1
|
8
|
my $self = shift( @_ ); |
288
|
4
|
|
|
|
|
21
|
my $r = $self->apache_request; |
289
|
4
|
50
|
|
|
|
88
|
if( $r ) |
290
|
|
|
|
|
|
|
{ |
291
|
0
|
|
|
|
|
0
|
return( $r->fname ); |
292
|
|
|
|
|
|
|
} |
293
|
|
|
|
|
|
|
else |
294
|
|
|
|
|
|
|
{ |
295
|
4
|
|
|
|
|
240
|
return( $self->{filepath} ); |
296
|
|
|
|
|
|
|
} |
297
|
|
|
|
|
|
|
} |
298
|
|
|
|
|
|
|
|
299
|
1
|
|
|
1
|
1
|
6
|
sub gid { return( shift->group ); } |
300
|
|
|
|
|
|
|
|
301
|
|
|
|
|
|
|
sub group |
302
|
|
|
|
|
|
|
{ |
303
|
2
|
|
|
2
|
1
|
5
|
my $self = shift( @_ ); |
304
|
2
|
|
|
|
|
6
|
my $f = $self->apr_finfo; |
305
|
2
|
50
|
|
|
|
181
|
if( $f ) |
306
|
|
|
|
|
|
|
{ |
307
|
0
|
|
|
|
|
0
|
return( $f->fname ); |
308
|
|
|
|
|
|
|
} |
309
|
|
|
|
|
|
|
else |
310
|
|
|
|
|
|
|
{ |
311
|
2
|
|
|
|
|
5
|
my $data = $self->{_data}; |
312
|
2
|
50
|
|
|
|
7
|
return( '' ) if( !scalar( @$data ) ); |
313
|
2
|
|
|
|
|
12
|
return( $data->[ FINFO_GID ] ); |
314
|
|
|
|
|
|
|
} |
315
|
|
|
|
|
|
|
} |
316
|
|
|
|
|
|
|
|
317
|
0
|
|
|
0
|
0
|
0
|
sub ino { return( shift->inode( @_ ) ); } |
318
|
|
|
|
|
|
|
|
319
|
|
|
|
|
|
|
sub inode |
320
|
|
|
|
|
|
|
{ |
321
|
1
|
|
|
1
|
1
|
3
|
my $self = shift( @_ ); |
322
|
1
|
|
|
|
|
5
|
my $f = $self->apr_finfo; |
323
|
1
|
50
|
|
|
|
85
|
if( $f ) |
324
|
|
|
|
|
|
|
{ |
325
|
0
|
|
|
|
|
0
|
return( $f->inode ); |
326
|
|
|
|
|
|
|
} |
327
|
|
|
|
|
|
|
else |
328
|
|
|
|
|
|
|
{ |
329
|
1
|
|
|
|
|
3
|
my $data = $self->{_data}; |
330
|
1
|
50
|
|
|
|
4
|
return( '' ) if( !scalar( @$data ) ); |
331
|
1
|
|
|
|
|
6
|
return( $data->[ FINFO_INODE ] ); |
332
|
|
|
|
|
|
|
} |
333
|
|
|
|
|
|
|
} |
334
|
|
|
|
|
|
|
|
335
|
1
|
|
|
1
|
1
|
4
|
sub is_block { return( shift->filetype == FILETYPE_BLK ); } |
336
|
|
|
|
|
|
|
|
337
|
1
|
|
|
1
|
1
|
4
|
sub is_char { return( shift->filetype == FILETYPE_CHR ); } |
338
|
|
|
|
|
|
|
|
339
|
2
|
|
|
2
|
1
|
8
|
sub is_dir { return( shift->filetype == FILETYPE_DIR ); } |
340
|
|
|
|
|
|
|
|
341
|
3
|
|
|
3
|
1
|
29
|
sub is_file { return( shift->filetype == FILETYPE_REG ); } |
342
|
|
|
|
|
|
|
|
343
|
1
|
|
|
1
|
1
|
4
|
sub is_link { return( shift->filetype == FILETYPE_LNK ); } |
344
|
|
|
|
|
|
|
|
345
|
1
|
|
|
1
|
1
|
4
|
sub is_pipe { return( shift->filetype == FILETYPE_PIPE ); } |
346
|
|
|
|
|
|
|
|
347
|
1
|
|
|
1
|
1
|
4
|
sub is_socket { return( shift->filetype == FILETYPE_SOCK ); } |
348
|
|
|
|
|
|
|
|
349
|
|
|
|
|
|
|
sub mime_type |
350
|
|
|
|
|
|
|
{ |
351
|
1
|
|
|
1
|
1
|
3
|
my $self = shift( @_ ); |
352
|
1
|
|
|
|
|
4
|
my $file = $self->filepath; |
353
|
1
|
|
|
|
|
26
|
my $m = Apache2::SSI::File::Type->new; |
354
|
1
|
|
|
|
|
6
|
return( $m->file( $file ) ); |
355
|
|
|
|
|
|
|
} |
356
|
|
|
|
|
|
|
|
357
|
|
|
|
|
|
|
sub mode |
358
|
|
|
|
|
|
|
{ |
359
|
3
|
|
|
3
|
1
|
21
|
my $self = shift( @_ ); |
360
|
3
|
|
|
|
|
65
|
my $f = $self->apr_finfo; |
361
|
3
|
50
|
|
|
|
387
|
if( $f ) |
362
|
|
|
|
|
|
|
{ |
363
|
|
|
|
|
|
|
# Something like 1860 |
364
|
0
|
|
|
|
|
0
|
my $hex = $f->protection; |
365
|
0
|
|
|
|
|
0
|
return( oct( sprintf( '%x', $hex ) ) ); |
366
|
|
|
|
|
|
|
} |
367
|
|
|
|
|
|
|
else |
368
|
|
|
|
|
|
|
{ |
369
|
3
|
|
|
|
|
24
|
my $data = $self->{_data}; |
370
|
3
|
50
|
|
|
|
25
|
return( '' ) if( !scalar( @$data ) ); |
371
|
3
|
|
|
|
|
40
|
return( $data->[ FINFO_MODE ] & 07777 ); |
372
|
|
|
|
|
|
|
} |
373
|
|
|
|
|
|
|
} |
374
|
|
|
|
|
|
|
|
375
|
|
|
|
|
|
|
sub mtime |
376
|
|
|
|
|
|
|
{ |
377
|
3
|
|
|
3
|
1
|
7
|
my $self = shift( @_ ); |
378
|
3
|
|
|
|
|
5
|
my $f = $self->apr_finfo; |
379
|
3
|
|
|
|
|
199
|
my $t; |
380
|
3
|
50
|
|
|
|
10
|
if( $f ) |
381
|
|
|
|
|
|
|
{ |
382
|
0
|
|
|
|
|
0
|
$t = $f->mtime; |
383
|
|
|
|
|
|
|
} |
384
|
|
|
|
|
|
|
else |
385
|
|
|
|
|
|
|
{ |
386
|
3
|
|
|
|
|
5
|
my $data = $self->{_data}; |
387
|
3
|
50
|
|
|
|
8
|
return( '' ) if( !scalar( @$data ) ); |
388
|
3
|
|
|
|
|
7
|
$t = $data->[ FINFO_MTIME ]; |
389
|
|
|
|
|
|
|
} |
390
|
3
|
|
|
|
|
11
|
return( $self->_datetime( $t ) ); |
391
|
|
|
|
|
|
|
} |
392
|
|
|
|
|
|
|
|
393
|
|
|
|
|
|
|
sub name |
394
|
|
|
|
|
|
|
{ |
395
|
3
|
|
|
3
|
1
|
7
|
my $self = shift( @_ ); |
396
|
3
|
|
|
|
|
14
|
my $f = $self->apr_finfo; |
397
|
3
|
50
|
|
|
|
290
|
if( $f ) |
398
|
|
|
|
|
|
|
{ |
399
|
0
|
|
0
|
|
|
0
|
return( $f->name || File::Basename::basename( $f->fname ) ); |
400
|
|
|
|
|
|
|
} |
401
|
|
|
|
|
|
|
else |
402
|
|
|
|
|
|
|
{ |
403
|
3
|
|
|
|
|
16
|
return( File::Basename::basename( $self->fname ) ); |
404
|
|
|
|
|
|
|
} |
405
|
|
|
|
|
|
|
} |
406
|
|
|
|
|
|
|
|
407
|
|
|
|
|
|
|
sub nlink |
408
|
|
|
|
|
|
|
{ |
409
|
1
|
|
|
1
|
1
|
935
|
my $self = shift( @_ ); |
410
|
1
|
|
|
|
|
5
|
my $f = $self->apr_finfo; |
411
|
1
|
50
|
|
|
|
85
|
if( $f ) |
412
|
|
|
|
|
|
|
{ |
413
|
0
|
|
|
|
|
0
|
return( $f->nlink ); |
414
|
|
|
|
|
|
|
} |
415
|
|
|
|
|
|
|
else |
416
|
|
|
|
|
|
|
{ |
417
|
1
|
|
|
|
|
3
|
my $data = $self->{_data}; |
418
|
1
|
50
|
|
|
|
4
|
return( '' ) if( !scalar( @$data ) ); |
419
|
1
|
|
|
|
|
6
|
return( $data->[ FINFO_NLINK ] ); |
420
|
|
|
|
|
|
|
} |
421
|
|
|
|
|
|
|
} |
422
|
|
|
|
|
|
|
|
423
|
|
|
|
|
|
|
sub protection |
424
|
|
|
|
|
|
|
{ |
425
|
1
|
|
|
1
|
1
|
4
|
my $self = shift( @_ ); |
426
|
1
|
|
|
|
|
3
|
my $f = $self->apr_finfo; |
427
|
1
|
50
|
|
|
|
91
|
if( $f ) |
428
|
|
|
|
|
|
|
{ |
429
|
|
|
|
|
|
|
## Will return something like 1860 (i.e. 744 = hex(1860)) |
430
|
0
|
|
|
|
|
0
|
return( $f->protection ); |
431
|
|
|
|
|
|
|
} |
432
|
|
|
|
|
|
|
else |
433
|
|
|
|
|
|
|
{ |
434
|
1
|
|
|
|
|
5
|
my @stat = CORE::stat( $self->filepath ); |
435
|
1
|
50
|
|
|
|
81
|
return( '' ) if( !scalar( @stat ) ); |
436
|
1
|
|
|
|
|
16
|
return( hex( sprintf( '%04o', $stat[2] & 07777 ) ) ); |
437
|
|
|
|
|
|
|
} |
438
|
|
|
|
|
|
|
} |
439
|
|
|
|
|
|
|
|
440
|
|
|
|
|
|
|
sub rdev |
441
|
|
|
|
|
|
|
{ |
442
|
0
|
|
|
0
|
1
|
0
|
my $self = shift( @_ ); |
443
|
0
|
|
|
|
|
0
|
my $f = $self->apr_finfo; |
444
|
0
|
0
|
|
|
|
0
|
if( $f ) |
445
|
|
|
|
|
|
|
{ |
446
|
0
|
|
|
|
|
0
|
return( ( CORE::stat( $self->{filepath} ) )[ FINFO_RDEV ] ); |
447
|
|
|
|
|
|
|
} |
448
|
|
|
|
|
|
|
else |
449
|
|
|
|
|
|
|
{ |
450
|
0
|
|
|
|
|
0
|
my $data = $self->{_data}; |
451
|
0
|
0
|
|
|
|
0
|
return( '' ) if( !scalar( @$data ) ); |
452
|
0
|
|
|
|
|
0
|
return( $data->[ FINFO_RDEV ] ); |
453
|
|
|
|
|
|
|
} |
454
|
|
|
|
|
|
|
} |
455
|
|
|
|
|
|
|
|
456
|
|
|
|
|
|
|
sub size |
457
|
|
|
|
|
|
|
{ |
458
|
6
|
|
|
6
|
1
|
1033
|
my $self = shift( @_ ); |
459
|
6
|
|
|
|
|
38
|
my $f = $self->apr_finfo; |
460
|
6
|
50
|
|
|
|
528
|
if( $f ) |
461
|
|
|
|
|
|
|
{ |
462
|
0
|
|
|
|
|
0
|
return( $f->size ); |
463
|
|
|
|
|
|
|
} |
464
|
|
|
|
|
|
|
else |
465
|
|
|
|
|
|
|
{ |
466
|
6
|
|
|
|
|
23
|
my $data = $self->{_data}; |
467
|
6
|
50
|
|
|
|
36
|
return( '' ) if( !scalar( @$data ) ); |
468
|
6
|
|
|
|
|
105
|
return( $data->[ FINFO_SIZE ] ); |
469
|
|
|
|
|
|
|
} |
470
|
|
|
|
|
|
|
} |
471
|
|
|
|
|
|
|
|
472
|
|
|
|
|
|
|
sub stat |
473
|
|
|
|
|
|
|
{ |
474
|
1
|
|
|
1
|
1
|
5
|
my $self = shift( @_ ); |
475
|
1
|
|
|
|
|
7
|
my $r = $self->apache_request; |
476
|
1
|
|
|
|
|
33
|
my $file = shift( @_ ); |
477
|
1
|
50
|
|
|
|
6
|
my $p = scalar( @_ ) ? { @_ } : {}; |
478
|
1
|
50
|
33
|
|
|
5
|
$p->{apache_request} = $r if( $r && !$p->{apache_request} ); |
479
|
1
|
|
|
|
|
8
|
return( $self->new( $file, $p ) ); |
480
|
|
|
|
|
|
|
} |
481
|
|
|
|
|
|
|
|
482
|
2
|
|
|
2
|
1
|
890
|
sub uid { return( shift->user ); } |
483
|
|
|
|
|
|
|
|
484
|
|
|
|
|
|
|
sub user |
485
|
|
|
|
|
|
|
{ |
486
|
3
|
|
|
3
|
1
|
7
|
my $self = shift( @_ ); |
487
|
3
|
|
|
|
|
11
|
my $f = $self->apr_finfo; |
488
|
3
|
50
|
|
|
|
244
|
if( $f ) |
489
|
|
|
|
|
|
|
{ |
490
|
0
|
|
|
|
|
0
|
return( $f->user ); |
491
|
|
|
|
|
|
|
} |
492
|
|
|
|
|
|
|
else |
493
|
|
|
|
|
|
|
{ |
494
|
3
|
|
|
|
|
8
|
my $data = $self->{_data}; |
495
|
3
|
50
|
|
|
|
10
|
return( '' ) if( !scalar( @$data ) ); |
496
|
3
|
|
|
|
|
20
|
return( $data->[ FINFO_UID ] ); |
497
|
|
|
|
|
|
|
} |
498
|
|
|
|
|
|
|
} |
499
|
|
|
|
|
|
|
|
500
|
|
|
|
|
|
|
sub _datetime |
501
|
|
|
|
|
|
|
{ |
502
|
5
|
|
|
5
|
|
10
|
my $self = shift( @_ ); |
503
|
5
|
|
|
|
|
8
|
my $t = shift( @_ ); |
504
|
5
|
50
|
|
|
|
13
|
return( $self->error( "No epoch time was provided." ) ) if( !length( $t ) ); |
505
|
5
|
50
|
|
|
|
32
|
return( $self->error( "Invalid epoch time provided \"$t\"." ) ) if( $t !~ /^\d+$/ ); |
506
|
5
|
|
|
|
|
6
|
try |
507
|
5
|
|
|
5
|
|
6
|
{ |
508
|
5
|
|
|
|
|
32
|
my $dt = DateTime->from_epoch( epoch => $t, time_zone => 'local' ); |
509
|
5
|
|
|
|
|
8058
|
my $fmt = DateTime::Format::Strptime->new( |
510
|
|
|
|
|
|
|
pattern => '%s', |
511
|
|
|
|
|
|
|
time_zone => 'local', |
512
|
|
|
|
|
|
|
); |
513
|
5
|
|
|
|
|
7707
|
$dt->set_formatter( $fmt ); |
514
|
5
|
|
|
|
|
270
|
return( Apache2::SSI::Datetime->new( $dt ) ); |
515
|
|
|
|
|
|
|
} |
516
|
5
|
100
|
|
|
|
26
|
catch( $e ) |
|
0
|
50
|
|
|
|
0
|
|
|
5
|
50
|
|
|
|
11
|
|
|
5
|
0
|
|
|
|
8
|
|
|
5
|
50
|
|
|
|
8
|
|
|
5
|
|
|
|
|
4
|
|
|
5
|
|
|
|
|
8
|
|
|
5
|
|
|
|
|
7
|
|
|
5
|
|
|
|
|
13
|
|
|
2
|
|
|
|
|
4
|
|
|
3
|
|
|
|
|
4
|
|
|
0
|
|
|
|
|
0
|
|
|
5
|
|
|
|
|
13
|
|
|
5
|
|
|
|
|
8
|
|
|
5
|
|
|
|
|
11
|
|
|
5
|
|
|
|
|
11
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
517
|
0
|
|
|
0
|
|
0
|
{ |
518
|
0
|
|
|
|
|
0
|
return( $self->error( "Unable to get the datetime object for \"$t\": $e" ) ); |
519
|
0
|
0
|
33
|
|
|
0
|
} |
|
0
|
0
|
33
|
|
|
0
|
|
|
0
|
100
|
|
|
|
0
|
|
|
0
|
50
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
5
|
|
|
|
|
86
|
|
|
5
|
|
|
|
|
65
|
|
520
|
|
|
|
|
|
|
} |
521
|
|
|
|
|
|
|
|
522
|
|
|
|
|
|
|
package Apache2::SSI::Datetime; |
523
|
|
|
|
|
|
|
BEGIN |
524
|
|
|
|
|
|
|
{ |
525
|
17
|
|
|
17
|
|
174
|
use strict; |
|
17
|
|
|
|
|
30
|
|
|
17
|
|
|
|
|
584
|
|
526
|
17
|
|
|
17
|
|
107
|
use warnings; |
|
17
|
|
|
|
|
27
|
|
|
17
|
|
|
|
|
1340
|
|
527
|
|
|
|
|
|
|
use overload ( |
528
|
5
|
|
|
5
|
|
32
|
q{""} => sub { $_[0]->{dt}->stringify }, |
529
|
|
|
|
|
|
|
bool => sub () { 1 }, |
530
|
17
|
|
|
|
|
133
|
fallback => 1, |
531
|
17
|
|
|
17
|
|
113
|
); |
|
17
|
|
|
|
|
29
|
|
532
|
17
|
|
|
17
|
|
3816
|
our( $ERROR ); |
533
|
|
|
|
|
|
|
}; |
534
|
|
|
|
|
|
|
|
535
|
|
|
|
|
|
|
sub new |
536
|
|
|
|
|
|
|
{ |
537
|
5
|
|
|
5
|
|
8
|
my $this = shift( @_ ); |
538
|
5
|
|
50
|
|
|
18
|
my $dt = shift( @_ ) || return; |
539
|
5
|
|
|
|
|
31
|
my $self = { dt => $dt }; |
540
|
5
|
|
33
|
|
|
36
|
return( bless( { dt => $dt } => ( ref( $this ) || $this ) ) ); |
541
|
|
|
|
|
|
|
} |
542
|
|
|
|
|
|
|
|
543
|
|
|
|
|
|
|
sub error |
544
|
|
|
|
|
|
|
{ |
545
|
5
|
|
|
5
|
|
8
|
my $self = shift( @_ ); |
546
|
5
|
50
|
|
|
|
10
|
if( @_ ) |
547
|
|
|
|
|
|
|
{ |
548
|
5
|
|
|
|
|
33
|
$self->{error} = $ERROR = join( '', @_ ); |
549
|
5
|
|
|
|
|
197
|
return; |
550
|
|
|
|
|
|
|
} |
551
|
0
|
|
0
|
|
|
0
|
return( $self->{error} || $ERROR ); |
552
|
|
|
|
|
|
|
} |
553
|
|
|
|
|
|
|
|
554
|
|
|
|
|
|
|
AUTOLOAD |
555
|
|
|
|
|
|
|
{ |
556
|
5
|
|
|
5
|
|
1914
|
my( $method ) = our $AUTOLOAD =~ /([^:]+)$/; |
557
|
17
|
|
|
17
|
|
128
|
no overloading; |
|
17
|
|
|
|
|
29
|
|
|
17
|
|
|
|
|
2275
|
|
558
|
5
|
|
|
|
|
11
|
my $self = shift( @_ ); |
559
|
5
|
|
33
|
|
|
16
|
my $class = ref( $self ) || $self; |
560
|
5
|
50
|
|
|
|
14
|
die( "DateTime object is gone !\n" ) if( !ref( $self->{dt} ) ); |
561
|
5
|
|
|
|
|
7
|
my $dt = $self->{dt}; |
562
|
5
|
50
|
|
|
|
22
|
if( $dt->can( $method ) ) |
563
|
|
|
|
|
|
|
{ |
564
|
0
|
|
|
|
|
0
|
return( $dt->$method( @_ ) ); |
565
|
|
|
|
|
|
|
} |
566
|
|
|
|
|
|
|
else |
567
|
|
|
|
|
|
|
{ |
568
|
5
|
|
|
|
|
20
|
return( $self->error( "No method \"$method\" available in DateTime" ) ); |
569
|
|
|
|
|
|
|
} |
570
|
|
|
|
|
|
|
}; |
571
|
|
|
|
|
|
|
|
572
|
|
|
|
|
|
|
1; |
573
|
|
|
|
|
|
|
|
574
|
|
|
|
|
|
|
__END__ |
575
|
|
|
|
|
|
|
|
576
|
|
|
|
|
|
|
=encoding utf-8 |
577
|
|
|
|
|
|
|
|
578
|
|
|
|
|
|
|
=head1 NAME |
579
|
|
|
|
|
|
|
|
580
|
|
|
|
|
|
|
Apache2::SSI::Finfo - Apache2 Server Side Include File Info Object Class |
581
|
|
|
|
|
|
|
|
582
|
|
|
|
|
|
|
=head1 SYNOPSIS |
583
|
|
|
|
|
|
|
|
584
|
|
|
|
|
|
|
my $finfo = Apache2::SSI::Finfo->new( '/some/file/path.html' ); |
585
|
|
|
|
|
|
|
# or with Apache |
586
|
|
|
|
|
|
|
use Apache2::RequestRec (); |
587
|
|
|
|
|
|
|
use apache2::RequestUtil (); |
588
|
|
|
|
|
|
|
my $r = Apache2::RequestUtil->request; |
589
|
|
|
|
|
|
|
my $finfo = Apache2::SSI::Finfo->new( '/some/file/path.html', apache_request => $r ); |
590
|
|
|
|
|
|
|
# Direct access to APR::Finfo |
591
|
|
|
|
|
|
|
my $apr = $finfo->apr_finfo; |
592
|
|
|
|
|
|
|
# Get access time as a DateTime object |
593
|
|
|
|
|
|
|
$finfo->atime; |
594
|
|
|
|
|
|
|
# Block site |
595
|
|
|
|
|
|
|
$finfo->blksize; |
596
|
|
|
|
|
|
|
# Number of blocks |
597
|
|
|
|
|
|
|
$finfo->blocks; |
598
|
|
|
|
|
|
|
if( $finfo->can_read ) |
599
|
|
|
|
|
|
|
{ |
600
|
|
|
|
|
|
|
# Do something |
601
|
|
|
|
|
|
|
} |
602
|
|
|
|
|
|
|
# Can also use |
603
|
|
|
|
|
|
|
$finfo->can_write; |
604
|
|
|
|
|
|
|
$finfo->can_exec; |
605
|
|
|
|
|
|
|
$finfo->csize; |
606
|
|
|
|
|
|
|
# Inode change time as a DateTime object |
607
|
|
|
|
|
|
|
$finfo->ctime; |
608
|
|
|
|
|
|
|
$finfo->dev; |
609
|
|
|
|
|
|
|
if( $finfo->exists ) |
610
|
|
|
|
|
|
|
{ |
611
|
|
|
|
|
|
|
# Do something |
612
|
|
|
|
|
|
|
} |
613
|
|
|
|
|
|
|
print "File path is: ", $finfo->filepath; |
614
|
|
|
|
|
|
|
if( $finfo->filetype == Apache2::SSI::Finfo::FILETYPE_NOFILE ) |
615
|
|
|
|
|
|
|
{ |
616
|
|
|
|
|
|
|
# File does not exist |
617
|
|
|
|
|
|
|
} |
618
|
|
|
|
|
|
|
# Same as $finfo->filepath |
619
|
|
|
|
|
|
|
print "File path is: ", $finfo->fname; |
620
|
|
|
|
|
|
|
print "File group id is: ", $finfo->gid; |
621
|
|
|
|
|
|
|
# Can also use $finfo->group which will yield the same result |
622
|
|
|
|
|
|
|
$finfo->ino; |
623
|
|
|
|
|
|
|
# or $finfo->inode; |
624
|
|
|
|
|
|
|
if( $finfo->is_block ) |
625
|
|
|
|
|
|
|
{ |
626
|
|
|
|
|
|
|
# Do something |
627
|
|
|
|
|
|
|
} |
628
|
|
|
|
|
|
|
elsif( $finfo->is_char ) |
629
|
|
|
|
|
|
|
{ |
630
|
|
|
|
|
|
|
# Do something else |
631
|
|
|
|
|
|
|
} |
632
|
|
|
|
|
|
|
elsif( $finfo->is_dir ) |
633
|
|
|
|
|
|
|
{ |
634
|
|
|
|
|
|
|
# It's a directory |
635
|
|
|
|
|
|
|
} |
636
|
|
|
|
|
|
|
elsif( $finfo->is_file ) |
637
|
|
|
|
|
|
|
{ |
638
|
|
|
|
|
|
|
# It's a regular file |
639
|
|
|
|
|
|
|
} |
640
|
|
|
|
|
|
|
elsif( $finfo->is_link ) |
641
|
|
|
|
|
|
|
{ |
642
|
|
|
|
|
|
|
# A file alias |
643
|
|
|
|
|
|
|
} |
644
|
|
|
|
|
|
|
elsif( $info->is_pipe ) |
645
|
|
|
|
|
|
|
{ |
646
|
|
|
|
|
|
|
# A Unix pipe ! |
647
|
|
|
|
|
|
|
} |
648
|
|
|
|
|
|
|
elsif( $finfo->is_socket ) |
649
|
|
|
|
|
|
|
{ |
650
|
|
|
|
|
|
|
# It's a socket |
651
|
|
|
|
|
|
|
} |
652
|
|
|
|
|
|
|
elsif( ( $info->mode & 0100 ) ) |
653
|
|
|
|
|
|
|
{ |
654
|
|
|
|
|
|
|
# Can execute |
655
|
|
|
|
|
|
|
} |
656
|
|
|
|
|
|
|
$finfo->mtime->strftime( '%A %d %B %Y %H:%m:%S' ); |
657
|
|
|
|
|
|
|
print "File base name is: ", $finfo->name; |
658
|
|
|
|
|
|
|
printf "File has %d links\n", $finfo->nlink; |
659
|
|
|
|
|
|
|
print "File permission in hexadecimal: ", $finfo->protection; |
660
|
|
|
|
|
|
|
$finfo->rdev; |
661
|
|
|
|
|
|
|
$finfo->size; |
662
|
|
|
|
|
|
|
my $new_object = $finfo->stat( '/some/other/file.txt' ); |
663
|
|
|
|
|
|
|
# Get the user id |
664
|
|
|
|
|
|
|
$finfo->uid; |
665
|
|
|
|
|
|
|
# Or |
666
|
|
|
|
|
|
|
$finfo->user; |
667
|
|
|
|
|
|
|
|
668
|
|
|
|
|
|
|
=head1 VERSION |
669
|
|
|
|
|
|
|
|
670
|
|
|
|
|
|
|
v0.1.1 |
671
|
|
|
|
|
|
|
|
672
|
|
|
|
|
|
|
=head1 DESCRIPTION |
673
|
|
|
|
|
|
|
|
674
|
|
|
|
|
|
|
This class provides a file info object oriented consistant whether it is accessed from Apache/mod_perl2 environment or from outside of it. |
675
|
|
|
|
|
|
|
|
676
|
|
|
|
|
|
|
The other advantage is that even if a non-existing file is provided, an object is returned. Obviously many of this module's methods will return an empty value since the file does not actually exist. This is an advantage, because one cannot create an L<APR::Finfo> object over a non-existing file. |
677
|
|
|
|
|
|
|
|
678
|
|
|
|
|
|
|
=head1 METHODS |
679
|
|
|
|
|
|
|
|
680
|
|
|
|
|
|
|
=head2 new |
681
|
|
|
|
|
|
|
|
682
|
|
|
|
|
|
|
This instantiate an object that is used to access other key methods. It takes a file path followed by the following parameters: |
683
|
|
|
|
|
|
|
|
684
|
|
|
|
|
|
|
=over 4 |
685
|
|
|
|
|
|
|
|
686
|
|
|
|
|
|
|
=item I<apache_request> |
687
|
|
|
|
|
|
|
|
688
|
|
|
|
|
|
|
This is the L<Apache2::RequestRec> object that is provided if running under mod_perl. |
689
|
|
|
|
|
|
|
|
690
|
|
|
|
|
|
|
it can be retrieved from L<Apache2::RequestUtil/request> or via L<Apache2::Filter/r> |
691
|
|
|
|
|
|
|
|
692
|
|
|
|
|
|
|
You can get this L<Apache2::RequestRec> object by requiring L<Apache2::RequestUtil> and calling its class method L<Apache2::RequestUtil/request> such as C<Apache2::RequestUtil->request> and assuming you have set C<PerlOptions +GlobalRequest> in your Apache Virtual Host configuration. |
693
|
|
|
|
|
|
|
|
694
|
|
|
|
|
|
|
Note that there is a main request object and subprocess request object, so to find out which one you are dealing with, use L<Apache2::RequestUtil/is_initial_req>, such as: |
695
|
|
|
|
|
|
|
|
696
|
|
|
|
|
|
|
use Apache2::RequestUtil (); # extends Apache2::RequestRec objects |
697
|
|
|
|
|
|
|
my $r = $r->is_initial_req ? $r : $r->main; |
698
|
|
|
|
|
|
|
|
699
|
|
|
|
|
|
|
=back |
700
|
|
|
|
|
|
|
|
701
|
|
|
|
|
|
|
=head2 apache_request |
702
|
|
|
|
|
|
|
|
703
|
|
|
|
|
|
|
Sets or gets the L<Apache2::RequestRec> object. As explained in the L</new> method, you can get this Apache object by requiring the package L<Apache2::RequestUtil> and calling L<Apache2::RequestUtil/request> such as C<Apache2::RequestUtil->request> assuming you have set C<PerlOptions +GlobalRequest> in your Apache Virtual Host configuration. |
704
|
|
|
|
|
|
|
|
705
|
|
|
|
|
|
|
When running under Apache mod_perl this is set automatically from the special L</handler> method, such as: |
706
|
|
|
|
|
|
|
|
707
|
|
|
|
|
|
|
my $r = $f->r; # $f is the Apache2::Filter object provided by Apache |
708
|
|
|
|
|
|
|
|
709
|
|
|
|
|
|
|
=head2 apr_finfo |
710
|
|
|
|
|
|
|
|
711
|
|
|
|
|
|
|
Sets or gets the L<APR::Finfo> object when running under Apache/mod_perl. Note that this value might be empty if the file does not exist. This is mentioned here for completeness only. |
712
|
|
|
|
|
|
|
|
713
|
|
|
|
|
|
|
=head2 atime |
714
|
|
|
|
|
|
|
|
715
|
|
|
|
|
|
|
Returns the file last access time as a L<Apache2::SSI::Datetime> object, which stringifies to its value in second since epoch. L<Apache2::SSI::Datetime> is just a wrapper around L<DateTime> to allow a L<DateTime> to be used in comparison with another non L<DateTime> value. |
716
|
|
|
|
|
|
|
|
717
|
|
|
|
|
|
|
For example: |
718
|
|
|
|
|
|
|
|
719
|
|
|
|
|
|
|
if( $finfo->atime > time() + 86400 ) |
720
|
|
|
|
|
|
|
{ |
721
|
|
|
|
|
|
|
print( "You are traveling in the future\n" ); |
722
|
|
|
|
|
|
|
} |
723
|
|
|
|
|
|
|
|
724
|
|
|
|
|
|
|
=head2 blksize |
725
|
|
|
|
|
|
|
|
726
|
|
|
|
|
|
|
Returns the preferred I/O size in bytes for interacting with the file. |
727
|
|
|
|
|
|
|
You can also use C<block_size>. |
728
|
|
|
|
|
|
|
|
729
|
|
|
|
|
|
|
=head2 blocks |
730
|
|
|
|
|
|
|
|
731
|
|
|
|
|
|
|
Returns the actual number of system-specific blocks allocated on disk (often, but not always, 512 bytes each). |
732
|
|
|
|
|
|
|
|
733
|
|
|
|
|
|
|
=head2 can_read |
734
|
|
|
|
|
|
|
|
735
|
|
|
|
|
|
|
Returns true if the the effective user can read the file. |
736
|
|
|
|
|
|
|
|
737
|
|
|
|
|
|
|
=head2 can_write |
738
|
|
|
|
|
|
|
|
739
|
|
|
|
|
|
|
Returns true if the the effective user can write to the file. |
740
|
|
|
|
|
|
|
|
741
|
|
|
|
|
|
|
=head2 can_exec |
742
|
|
|
|
|
|
|
|
743
|
|
|
|
|
|
|
Returns true if the the effective user can execute the file. Same as L</execute> |
744
|
|
|
|
|
|
|
|
745
|
|
|
|
|
|
|
=head2 can_execute |
746
|
|
|
|
|
|
|
|
747
|
|
|
|
|
|
|
Returns true if the the effective user can execute the file. Same as L</exec> |
748
|
|
|
|
|
|
|
|
749
|
|
|
|
|
|
|
=head2 csize |
750
|
|
|
|
|
|
|
|
751
|
|
|
|
|
|
|
Returns the total size of file, in bytes. Same as L</size> |
752
|
|
|
|
|
|
|
|
753
|
|
|
|
|
|
|
=head2 ctime |
754
|
|
|
|
|
|
|
|
755
|
|
|
|
|
|
|
Returns the file inode change time as a L<Apache2::SSI::Datetime> object, which stringifies to its value in second since epoch. L<Apache2::SSI::Datetime> is just a wrapper around L<DateTime> to allow a L<DateTime> to be used in comparison with another non L<DateTime> value. |
756
|
|
|
|
|
|
|
|
757
|
|
|
|
|
|
|
=head2 dev |
758
|
|
|
|
|
|
|
|
759
|
|
|
|
|
|
|
Returns the device number of filesystem. Same as L</dev> |
760
|
|
|
|
|
|
|
|
761
|
|
|
|
|
|
|
=head2 device |
762
|
|
|
|
|
|
|
|
763
|
|
|
|
|
|
|
Returns the device number of filesystem. Same as L</device> |
764
|
|
|
|
|
|
|
|
765
|
|
|
|
|
|
|
=head2 exists |
766
|
|
|
|
|
|
|
|
767
|
|
|
|
|
|
|
Returns true if the filetype is not L</FILETYPE_NOFILE> |
768
|
|
|
|
|
|
|
|
769
|
|
|
|
|
|
|
=head2 filepath |
770
|
|
|
|
|
|
|
|
771
|
|
|
|
|
|
|
Returns the file path as a string. Same as L</fname> |
772
|
|
|
|
|
|
|
|
773
|
|
|
|
|
|
|
=head2 filetype |
774
|
|
|
|
|
|
|
|
775
|
|
|
|
|
|
|
Returns the file type which is one of the L</CONSTANTS> below. |
776
|
|
|
|
|
|
|
|
777
|
|
|
|
|
|
|
=head2 fname |
778
|
|
|
|
|
|
|
|
779
|
|
|
|
|
|
|
Returns the file path as a string. Same as L</filepath> |
780
|
|
|
|
|
|
|
|
781
|
|
|
|
|
|
|
=head2 gid |
782
|
|
|
|
|
|
|
|
783
|
|
|
|
|
|
|
Returns the numeric group ID of file's owner. Same as L</group> |
784
|
|
|
|
|
|
|
|
785
|
|
|
|
|
|
|
=head2 group |
786
|
|
|
|
|
|
|
|
787
|
|
|
|
|
|
|
Returns the numeric group ID of file's owner. Same as L</gid> |
788
|
|
|
|
|
|
|
|
789
|
|
|
|
|
|
|
=head2 inode |
790
|
|
|
|
|
|
|
|
791
|
|
|
|
|
|
|
Returns the inode number. |
792
|
|
|
|
|
|
|
|
793
|
|
|
|
|
|
|
=head2 is_block |
794
|
|
|
|
|
|
|
|
795
|
|
|
|
|
|
|
Returns true if this is a block file, false otherwise. |
796
|
|
|
|
|
|
|
|
797
|
|
|
|
|
|
|
=head2 is_char |
798
|
|
|
|
|
|
|
|
799
|
|
|
|
|
|
|
Returns true if this is a character file, false otherwise. |
800
|
|
|
|
|
|
|
|
801
|
|
|
|
|
|
|
=head2 is_dir |
802
|
|
|
|
|
|
|
|
803
|
|
|
|
|
|
|
Returns true if this is a directory, false otherwise. |
804
|
|
|
|
|
|
|
|
805
|
|
|
|
|
|
|
=head2 is_file |
806
|
|
|
|
|
|
|
|
807
|
|
|
|
|
|
|
Returns true if this is a regular file, false otherwise. |
808
|
|
|
|
|
|
|
|
809
|
|
|
|
|
|
|
=head2 is_link |
810
|
|
|
|
|
|
|
|
811
|
|
|
|
|
|
|
Returns true if this is a symbolic link, false otherwise. |
812
|
|
|
|
|
|
|
|
813
|
|
|
|
|
|
|
=head2 is_pipe |
814
|
|
|
|
|
|
|
|
815
|
|
|
|
|
|
|
Returns true if this is a pipe, false otherwise. |
816
|
|
|
|
|
|
|
|
817
|
|
|
|
|
|
|
=head2 is_socket |
818
|
|
|
|
|
|
|
|
819
|
|
|
|
|
|
|
Returns true if this is a socket, false otherwise. |
820
|
|
|
|
|
|
|
|
821
|
|
|
|
|
|
|
=head2 mime_type |
822
|
|
|
|
|
|
|
|
823
|
|
|
|
|
|
|
Using L<Apache2::SSI::File::Type>, this guess the file mime type and returns it. |
824
|
|
|
|
|
|
|
|
825
|
|
|
|
|
|
|
=head2 mode |
826
|
|
|
|
|
|
|
|
827
|
|
|
|
|
|
|
Returns the file mode. This is equivalent to the mode & 07777, ie without the file type bit. |
828
|
|
|
|
|
|
|
|
829
|
|
|
|
|
|
|
So you could do something like: |
830
|
|
|
|
|
|
|
|
831
|
|
|
|
|
|
|
if( $finfo->mode & 0100 ) |
832
|
|
|
|
|
|
|
{ |
833
|
|
|
|
|
|
|
print( "Owner can execute\n" ); |
834
|
|
|
|
|
|
|
} |
835
|
|
|
|
|
|
|
if( $finfo->mode & 0001 ) |
836
|
|
|
|
|
|
|
{ |
837
|
|
|
|
|
|
|
print( "Everyone can execute too!\n" ); |
838
|
|
|
|
|
|
|
} |
839
|
|
|
|
|
|
|
|
840
|
|
|
|
|
|
|
=head2 mtime |
841
|
|
|
|
|
|
|
|
842
|
|
|
|
|
|
|
Returns the file last modify time as a L<Apache2::SSI::Datetime> object, which stringifies to its value in second since epoch. L<Apache2::SSI::Datetime> is just a wrapper around L<DateTime> to allow a L<DateTime> to be used in comparison with another non L<DateTime> value. |
843
|
|
|
|
|
|
|
|
844
|
|
|
|
|
|
|
=head2 name |
845
|
|
|
|
|
|
|
|
846
|
|
|
|
|
|
|
Returns the file base name. So if the file is C</home/john/www/some/file.html> this would return C<file.html> |
847
|
|
|
|
|
|
|
|
848
|
|
|
|
|
|
|
Interesting to note that L<APR::Finfo/name> which is advertised as returning the file base name, actually returns just an empty string. With this module, this uses a workaround to provide the proper value. It use L<File::Basename/basename> on the value returned by L</fname> |
849
|
|
|
|
|
|
|
|
850
|
|
|
|
|
|
|
=head2 nlink |
851
|
|
|
|
|
|
|
|
852
|
|
|
|
|
|
|
Returns the number of (hard) links to the file. |
853
|
|
|
|
|
|
|
|
854
|
|
|
|
|
|
|
=head2 protection |
855
|
|
|
|
|
|
|
|
856
|
|
|
|
|
|
|
=head2 rdev |
857
|
|
|
|
|
|
|
|
858
|
|
|
|
|
|
|
Returns the device identifier (special files only). |
859
|
|
|
|
|
|
|
|
860
|
|
|
|
|
|
|
=head2 size |
861
|
|
|
|
|
|
|
|
862
|
|
|
|
|
|
|
Returns the total size of file, in bytes. Same as L</csize> |
863
|
|
|
|
|
|
|
|
864
|
|
|
|
|
|
|
=head2 stat |
865
|
|
|
|
|
|
|
|
866
|
|
|
|
|
|
|
Provided with a file path and this returns a new L<Apache2::SSI::Finfo> object. |
867
|
|
|
|
|
|
|
|
868
|
|
|
|
|
|
|
=head2 uid |
869
|
|
|
|
|
|
|
|
870
|
|
|
|
|
|
|
=head2 user |
871
|
|
|
|
|
|
|
|
872
|
|
|
|
|
|
|
Returns the numeric user ID of file's owner. Same as L</uid> |
873
|
|
|
|
|
|
|
|
874
|
|
|
|
|
|
|
=head2 uid |
875
|
|
|
|
|
|
|
|
876
|
|
|
|
|
|
|
Returns the numeric user ID of file's owner. Same as L</user> |
877
|
|
|
|
|
|
|
|
878
|
|
|
|
|
|
|
=head1 CONSTANTS |
879
|
|
|
|
|
|
|
|
880
|
|
|
|
|
|
|
=head2 FILETYPE_NOFILE |
881
|
|
|
|
|
|
|
|
882
|
|
|
|
|
|
|
File type constant to indicate the file does not exist. |
883
|
|
|
|
|
|
|
|
884
|
|
|
|
|
|
|
=head2 FILETYPE_REG |
885
|
|
|
|
|
|
|
|
886
|
|
|
|
|
|
|
Regular file |
887
|
|
|
|
|
|
|
|
888
|
|
|
|
|
|
|
=head2 FILETYPE_DIR |
889
|
|
|
|
|
|
|
|
890
|
|
|
|
|
|
|
The element is a directory |
891
|
|
|
|
|
|
|
|
892
|
|
|
|
|
|
|
=head2 FILETYPE_CHR |
893
|
|
|
|
|
|
|
|
894
|
|
|
|
|
|
|
The element is a character block |
895
|
|
|
|
|
|
|
|
896
|
|
|
|
|
|
|
=head2 FILETYPE_BLK |
897
|
|
|
|
|
|
|
|
898
|
|
|
|
|
|
|
A block device |
899
|
|
|
|
|
|
|
|
900
|
|
|
|
|
|
|
=head2 FILETYPE_PIPE |
901
|
|
|
|
|
|
|
|
902
|
|
|
|
|
|
|
The file is a FIFO or a pipe |
903
|
|
|
|
|
|
|
|
904
|
|
|
|
|
|
|
=head2 FILETYPE_LNK |
905
|
|
|
|
|
|
|
|
906
|
|
|
|
|
|
|
The file is a symbolic link |
907
|
|
|
|
|
|
|
|
908
|
|
|
|
|
|
|
=head2 FILETYPE_SOCK |
909
|
|
|
|
|
|
|
|
910
|
|
|
|
|
|
|
The file is a (unix domain) socket |
911
|
|
|
|
|
|
|
|
912
|
|
|
|
|
|
|
=head2 FILETYPE_UNKFILE |
913
|
|
|
|
|
|
|
|
914
|
|
|
|
|
|
|
The file is of some other unknown type or the type cannot be determined |
915
|
|
|
|
|
|
|
|
916
|
|
|
|
|
|
|
=head1 AUTHOR |
917
|
|
|
|
|
|
|
|
918
|
|
|
|
|
|
|
Jacques Deguest E<lt>F<jack@deguest.jp>E<gt> |
919
|
|
|
|
|
|
|
|
920
|
|
|
|
|
|
|
CPAN ID: jdeguest |
921
|
|
|
|
|
|
|
|
922
|
|
|
|
|
|
|
L<https://git.deguest.jp/jack/Apache2-SSI> |
923
|
|
|
|
|
|
|
|
924
|
|
|
|
|
|
|
=head1 SEE ALSO |
925
|
|
|
|
|
|
|
|
926
|
|
|
|
|
|
|
L<Apache2::SSI::File>, L<Apache2::SSI::URI>, L<Apache2::SSI> |
927
|
|
|
|
|
|
|
|
928
|
|
|
|
|
|
|
mod_include, mod_perl(3), L<APR::Finfo>, L<perlfunc/stat> |
929
|
|
|
|
|
|
|
L<https://httpd.apache.org/docs/current/en/mod/mod_include.html>, |
930
|
|
|
|
|
|
|
L<https://httpd.apache.org/docs/current/en/howto/ssi.html>, |
931
|
|
|
|
|
|
|
L<https://httpd.apache.org/docs/current/en/expr.html> |
932
|
|
|
|
|
|
|
L<https://perl.apache.org/docs/2.0/user/handlers/filters.html#C_PerlOutputFilterHandler_> |
933
|
|
|
|
|
|
|
|
934
|
|
|
|
|
|
|
=head1 COPYRIGHT & LICENSE |
935
|
|
|
|
|
|
|
|
936
|
|
|
|
|
|
|
Copyright (c) 2020-2021 DEGUEST Pte. Ltd. |
937
|
|
|
|
|
|
|
|
938
|
|
|
|
|
|
|
You can use, copy, modify and redistribute this package and associated |
939
|
|
|
|
|
|
|
files under the same terms as Perl itself. |
940
|
|
|
|
|
|
|
|
941
|
|
|
|
|
|
|
=cut |