line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package File::DataClass::IO; |
2
|
|
|
|
|
|
|
|
3
|
7
|
|
|
7
|
|
134676
|
use 5.010001; |
|
7
|
|
|
|
|
24
|
|
4
|
|
|
|
|
|
|
|
5
|
7
|
|
|
7
|
|
29
|
use Cwd qw( ); |
|
7
|
|
|
|
|
11
|
|
|
7
|
|
|
|
|
102
|
|
6
|
7
|
|
|
7
|
|
26
|
use English qw( -no_match_vars ); |
|
7
|
|
|
|
|
7
|
|
|
7
|
|
|
|
|
38
|
|
7
|
7
|
|
|
7
|
|
2007
|
use Fcntl qw( :flock :seek ); |
|
7
|
|
|
|
|
12
|
|
|
7
|
|
|
|
|
844
|
|
8
|
7
|
|
|
7
|
|
30
|
use File::Basename ( ); |
|
7
|
|
|
|
|
11
|
|
|
7
|
|
|
|
|
115
|
|
9
|
7
|
|
|
7
|
|
23
|
use File::Copy ( ); |
|
7
|
|
|
|
|
38
|
|
|
7
|
|
|
|
|
158
|
|
10
|
7
|
|
|
|
|
664
|
use File::DataClass::Constants qw( EXCEPTION_CLASS FALSE LOCK_BLOCKING |
11
|
|
|
|
|
|
|
LOCK_NONBLOCKING NO_UMASK_STACK NUL |
12
|
7
|
|
|
7
|
|
1647
|
PERMS STAT_FIELDS TILDE TRUE ); |
|
7
|
|
|
|
|
17
|
|
13
|
7
|
|
|
|
|
519
|
use File::DataClass::Functions qw( ensure_class_loaded first_char is_arrayref |
14
|
|
|
|
|
|
|
is_coderef is_hashref is_member is_mswin |
15
|
7
|
|
|
7
|
|
1988
|
is_ntfs thread_id throw ); |
|
7
|
|
|
|
|
14
|
|
16
|
7
|
|
|
7
|
|
33
|
use File::Spec ( ); |
|
7
|
|
|
|
|
10
|
|
|
7
|
|
|
|
|
119
|
|
17
|
7
|
|
|
7
|
|
1483
|
use File::Spec::Functions qw( curdir updir ); |
|
7
|
|
|
|
|
9
|
|
|
7
|
|
|
|
|
289
|
|
18
|
7
|
|
|
7
|
|
3294
|
use IO::Dir; |
|
7
|
|
|
|
|
94777
|
|
|
7
|
|
|
|
|
312
|
|
19
|
7
|
|
|
7
|
|
44
|
use IO::File; |
|
7
|
|
|
|
|
11
|
|
|
7
|
|
|
|
|
927
|
|
20
|
7
|
|
|
7
|
|
33
|
use IO::Handle; |
|
7
|
|
|
|
|
8
|
|
|
7
|
|
|
|
|
226
|
|
21
|
7
|
|
|
7
|
|
34
|
use List::Util qw( first ); |
|
7
|
|
|
|
|
18
|
|
|
7
|
|
|
|
|
333
|
|
22
|
7
|
|
|
7
|
|
28
|
use Scalar::Util qw( blessed ); |
|
7
|
|
|
|
|
11
|
|
|
7
|
|
|
|
|
249
|
|
23
|
7
|
|
|
7
|
|
27
|
use Sub::Install qw( install_sub ); |
|
7
|
|
|
|
|
8
|
|
|
7
|
|
|
|
|
62
|
|
24
|
7
|
|
|
7
|
|
673
|
use Type::Utils qw( enum ); |
|
7
|
|
|
|
|
7
|
|
|
7
|
|
|
|
|
66
|
|
25
|
7
|
|
|
7
|
|
2866
|
use Unexpected::Functions qw( InvocantUndefined PathNotFound Unspecified ); |
|
7
|
|
|
|
|
9
|
|
|
7
|
|
|
|
|
55
|
|
26
|
7
|
|
|
|
|
48
|
use Unexpected::Types qw( ArrayRef Bool CodeRef Int Maybe Object |
27
|
7
|
|
|
7
|
|
1862
|
PositiveInt RegexpRef SimpleStr Str ); |
|
7
|
|
|
|
|
10
|
|
28
|
7
|
|
|
7
|
|
6894
|
use Moo; |
|
7
|
|
|
|
|
51
|
|
|
7
|
|
|
|
|
57
|
|
29
|
|
|
|
|
|
|
|
30
|
7
|
|
|
7
|
|
2578
|
use namespace::clean -except => [ 'meta' ]; |
|
7
|
|
|
|
|
10
|
|
|
7
|
|
|
|
|
109
|
|
31
|
1019
|
|
|
1019
|
|
21508
|
use overload '""' => sub { $_[ 0 ]->as_string }, |
32
|
1912
|
|
|
1912
|
|
9011
|
'bool' => sub { $_[ 0 ]->as_boolean }, |
33
|
7
|
|
|
7
|
|
5049
|
'fallback' => TRUE; |
|
7
|
|
|
|
|
8
|
|
|
7
|
|
|
|
|
62
|
|
34
|
|
|
|
|
|
|
|
35
|
|
|
|
|
|
|
my $IO_LOCK = enum 'IO_Lock' => [ FALSE, LOCK_BLOCKING, LOCK_NONBLOCKING ]; |
36
|
|
|
|
|
|
|
my $IO_MODE = enum 'IO_Mode' => [ qw( a a+ r r+ w w+ ) ]; |
37
|
|
|
|
|
|
|
my $IO_TYPE = enum 'IO_Type' => [ qw( dir file ) ]; |
38
|
|
|
|
|
|
|
|
39
|
|
|
|
|
|
|
# Attribute constructors |
40
|
|
|
|
|
|
|
my $_build_dir_pattern = sub { |
41
|
124
|
|
|
124
|
|
681
|
my $cd = curdir; my $ud = updir; qr{ \A (?: \Q${cd}\E | \Q${ud}\E ) \z }mx; |
|
124
|
|
|
|
|
110
|
|
|
124
|
|
|
|
|
2050
|
|
42
|
|
|
|
|
|
|
}; |
43
|
|
|
|
|
|
|
|
44
|
|
|
|
|
|
|
my $_catfile = sub { |
45
|
|
|
|
|
|
|
return File::Spec->catfile( map { defined( $_ ) ? $_ : NUL } @_ ); |
46
|
|
|
|
|
|
|
}; |
47
|
|
|
|
|
|
|
|
48
|
|
|
|
|
|
|
my $_expand_tilde = sub { |
49
|
|
|
|
|
|
|
(my $path = $_[ 0 ]) =~ m{ \A ([~] [^/\\]*) .* }mx; |
50
|
|
|
|
|
|
|
|
51
|
|
|
|
|
|
|
my ($dir) = glob( $1 ); $path =~ s{ \A ([~] [^/\\]*) }{$dir}mx; |
52
|
|
|
|
|
|
|
|
53
|
|
|
|
|
|
|
return $path; |
54
|
|
|
|
|
|
|
}; |
55
|
|
|
|
|
|
|
|
56
|
|
|
|
|
|
|
my $_coerce_name = sub { |
57
|
|
|
|
|
|
|
my $name = shift; |
58
|
|
|
|
|
|
|
|
59
|
|
|
|
|
|
|
not defined $name and return; |
60
|
|
|
|
|
|
|
is_coderef $name and $name = $name->(); |
61
|
|
|
|
|
|
|
blessed $name and $name = "${name}"; |
62
|
|
|
|
|
|
|
is_arrayref $name and $name = $_catfile->( @{ $name } ); |
63
|
|
|
|
|
|
|
first_char $name eq TILDE and $name = $_expand_tilde->( $name ); |
64
|
|
|
|
|
|
|
curdir eq $name and $name = Cwd::getcwd(); |
65
|
|
|
|
|
|
|
CORE::length $name > 1 and $name =~ s{ [/\\] \z }{}mx; |
66
|
|
|
|
|
|
|
return $name; |
67
|
|
|
|
|
|
|
}; |
68
|
|
|
|
|
|
|
|
69
|
|
|
|
|
|
|
# Public attributes |
70
|
|
|
|
|
|
|
has 'autoclose' => is => 'lazy', isa => Bool, default => TRUE ; |
71
|
|
|
|
|
|
|
has 'have_lock' => is => 'rwp', isa => Bool, default => FALSE ; |
72
|
|
|
|
|
|
|
has 'io_handle' => is => 'rwp', isa => Maybe[Object] ; |
73
|
|
|
|
|
|
|
has 'is_open' => is => 'rwp', isa => Bool, default => FALSE ; |
74
|
|
|
|
|
|
|
has 'mode' => is => 'rwp', isa => $IO_MODE | PositiveInt, |
75
|
|
|
|
|
|
|
default => 'r' ; |
76
|
|
|
|
|
|
|
has 'name' => is => 'rwp', isa => SimpleStr, default => NUL, |
77
|
|
|
|
|
|
|
coerce => $_coerce_name, lazy => TRUE ; |
78
|
|
|
|
|
|
|
has '_perms' => is => 'rwp', isa => PositiveInt, default => PERMS, |
79
|
|
|
|
|
|
|
init_arg => 'perms' ; |
80
|
|
|
|
|
|
|
has 'reverse' => is => 'lazy', isa => Bool, default => FALSE ; |
81
|
|
|
|
|
|
|
has 'sort' => is => 'lazy', isa => Bool, default => TRUE ; |
82
|
|
|
|
|
|
|
has 'type' => is => 'rwp', isa => Maybe[$IO_TYPE] ; |
83
|
|
|
|
|
|
|
|
84
|
|
|
|
|
|
|
# Private attributes |
85
|
|
|
|
|
|
|
has '_assert' => is => 'rw', isa => Bool, default => FALSE ; |
86
|
|
|
|
|
|
|
has '_atomic' => is => 'rw', isa => Bool, default => FALSE ; |
87
|
|
|
|
|
|
|
has '_atomic_infix' => is => 'rw', isa => SimpleStr, default => 'B_*' ; |
88
|
|
|
|
|
|
|
has '_backwards' => is => 'rw', isa => Bool, default => FALSE ; |
89
|
|
|
|
|
|
|
has '_block_size' => is => 'rw', isa => PositiveInt, default => 1024 ; |
90
|
|
|
|
|
|
|
has '_chomp' => is => 'rw', isa => Bool, default => FALSE ; |
91
|
|
|
|
|
|
|
has '_deep' => is => 'rw', isa => Bool, default => FALSE ; |
92
|
|
|
|
|
|
|
has '_dir_pattern' => is => 'lazy', isa => RegexpRef, |
93
|
|
|
|
|
|
|
builder => $_build_dir_pattern ; |
94
|
|
|
|
|
|
|
has '_filter' => is => 'rw', isa => Maybe[CodeRef] ; |
95
|
|
|
|
|
|
|
has '_layers' => is => 'ro', isa => ArrayRef[SimpleStr], |
96
|
588
|
|
|
588
|
|
70438
|
builder => sub { [] } ; |
97
|
|
|
|
|
|
|
has '_lock' => is => 'rw', isa => $IO_LOCK, default => FALSE ; |
98
|
|
|
|
|
|
|
has '_no_follow' => is => 'rw', isa => Bool, default => FALSE ; |
99
|
|
|
|
|
|
|
has '_separator' => is => 'rw', isa => Str, default => $RS ; |
100
|
|
|
|
|
|
|
has '_umask' => is => 'ro', isa => ArrayRef[Int], |
101
|
588
|
|
|
588
|
|
46124
|
builder => sub { [] } ; |
102
|
|
|
|
|
|
|
|
103
|
|
|
|
|
|
|
# Construction |
104
|
|
|
|
|
|
|
my @ARG_NAMES = qw( name mode perms ); |
105
|
|
|
|
|
|
|
|
106
|
|
|
|
|
|
|
my $_clone_one_of_us = sub { |
107
|
|
|
|
|
|
|
my ($self, $params) = @_; |
108
|
|
|
|
|
|
|
|
109
|
|
|
|
|
|
|
$self->autoclose; $self->reverse; $self->sort; # Force evaluation |
110
|
|
|
|
|
|
|
|
111
|
|
|
|
|
|
|
my $clone = { %{ $self }, %{ $params // {} } }; |
112
|
|
|
|
|
|
|
my $perms = delete $clone->{_perms}; $clone->{perms} //= $perms; |
113
|
|
|
|
|
|
|
|
114
|
|
|
|
|
|
|
return $clone; |
115
|
|
|
|
|
|
|
}; |
116
|
|
|
|
|
|
|
|
117
|
|
|
|
|
|
|
my $_constructor = sub { |
118
|
|
|
|
|
|
|
my $self = shift; return (blessed $self)->new( @_ ); |
119
|
|
|
|
|
|
|
}; |
120
|
|
|
|
|
|
|
|
121
|
|
|
|
|
|
|
my $_inline_args = sub { |
122
|
|
|
|
|
|
|
my $n = shift; return (map { $ARG_NAMES[ $_ ] => $_[ $_ ] } 0 .. $n - 1); |
123
|
|
|
|
|
|
|
}; |
124
|
|
|
|
|
|
|
|
125
|
|
|
|
|
|
|
my $_is_one_of_us = sub { |
126
|
|
|
|
|
|
|
return (blessed $_[ 0 ]) && $_[ 0 ]->isa( __PACKAGE__ ); |
127
|
|
|
|
|
|
|
}; |
128
|
|
|
|
|
|
|
|
129
|
|
|
|
|
|
|
sub BUILDARGS { # Differentiate constructor method signatures |
130
|
591
|
|
|
591
|
1
|
71704
|
my $class = shift; my $n = 0; $n++ while (defined $_[ $n ]); |
|
591
|
|
|
|
|
591
|
|
|
591
|
|
|
|
|
2064
|
|
131
|
|
|
|
|
|
|
|
132
|
|
|
|
|
|
|
return ( $n == 0 ) ? { io_handle => IO::Handle->new } |
133
|
|
|
|
|
|
|
: $_is_one_of_us->( $_[ 0 ] ) ? $_clone_one_of_us->( @_ ) |
134
|
2
|
|
|
|
|
30
|
: is_hashref( $_[ 0 ] ) ? { %{ $_[ 0 ] } } |
135
|
|
|
|
|
|
|
: ( $n == 1 ) ? { $_inline_args->( 1, @_ ) } |
136
|
591
|
100
|
|
|
|
1397
|
: is_hashref( $_[ 1 ] ) ? { name => $_[ 0 ], %{ $_[ 1 ] } } |
|
345
|
100
|
|
|
|
5161
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
137
|
|
|
|
|
|
|
: ( $n == 2 ) ? { $_inline_args->( 2, @_ ) } |
138
|
|
|
|
|
|
|
: ( $n == 3 ) ? { $_inline_args->( 3, @_ ) } |
139
|
|
|
|
|
|
|
: { @_ }; |
140
|
|
|
|
|
|
|
} |
141
|
|
|
|
|
|
|
|
142
|
|
|
|
|
|
|
sub BUILD { |
143
|
590
|
|
|
590
|
1
|
26067
|
my $self = shift; my $handle = $self->io_handle; |
|
590
|
|
|
|
|
960
|
|
144
|
|
|
|
|
|
|
|
145
|
590
|
100
|
100
|
|
|
7656
|
not $self->name and $handle and $self->_set_is_open( $handle->opened ); |
146
|
|
|
|
|
|
|
|
147
|
590
|
|
|
|
|
6665
|
return; |
148
|
|
|
|
|
|
|
} |
149
|
|
|
|
|
|
|
|
150
|
|
|
|
|
|
|
sub clone { |
151
|
2
|
100
|
|
2
|
1
|
308
|
my ($self, @args) = @_; blessed $self or throw 'Clone is an object method'; |
|
2
|
|
|
|
|
25
|
|
152
|
|
|
|
|
|
|
|
153
|
1
|
|
|
|
|
3
|
return $self->$_constructor( $self, @args ); |
154
|
|
|
|
|
|
|
} |
155
|
|
|
|
|
|
|
|
156
|
|
|
|
|
|
|
sub DEMOLISH { |
157
|
589
|
|
|
589
|
1
|
97147
|
my ($self, $gd) = @_; |
158
|
|
|
|
|
|
|
|
159
|
589
|
50
|
|
|
|
1032
|
$gd and return; # uncoverable branch true |
160
|
589
|
100
|
|
|
|
6987
|
$self->_atomic ? $self->delete : $self->close; |
161
|
589
|
|
|
|
|
6722
|
return; |
162
|
|
|
|
|
|
|
} |
163
|
|
|
|
|
|
|
|
164
|
|
|
|
|
|
|
sub import { |
165
|
14
|
|
|
14
|
|
71
|
my ($class, @wanted) = @_; my $package = caller; |
|
14
|
|
|
|
|
31
|
|
166
|
|
|
|
|
|
|
|
167
|
|
|
|
|
|
|
(not defined $wanted[ 0 ] or $wanted[ 0 ] eq 'io') |
168
|
|
|
|
|
|
|
and install_sub { into => $package, as => 'io', code => sub (;@) { |
169
|
233
|
|
|
233
|
|
68622
|
return $class->new( @_ ); |
170
|
14
|
100
|
100
|
|
|
182
|
} }; |
171
|
|
|
|
|
|
|
|
172
|
14
|
|
|
|
|
110371
|
return; |
173
|
|
|
|
|
|
|
} |
174
|
|
|
|
|
|
|
|
175
|
|
|
|
|
|
|
# Private functions |
176
|
|
|
|
|
|
|
my $_should_include_path = sub { |
177
|
|
|
|
|
|
|
return (not defined $_[ 0 ] or (map { $_[ 0 ]->() } ($_[ 1 ]))[ 0 ]); |
178
|
|
|
|
|
|
|
}; |
179
|
|
|
|
|
|
|
|
180
|
|
|
|
|
|
|
# Private methods |
181
|
|
|
|
|
|
|
my $_all_file_contents = sub { |
182
|
|
|
|
|
|
|
my $self = shift; $self->is_open or $self->assert_open; |
183
|
|
|
|
|
|
|
|
184
|
|
|
|
|
|
|
local $RS = undef; my $content = $self->io_handle->getline; |
185
|
|
|
|
|
|
|
|
186
|
|
|
|
|
|
|
$self->error_check; $self->autoclose and $self->close; |
187
|
|
|
|
|
|
|
|
188
|
|
|
|
|
|
|
return $content; |
189
|
|
|
|
|
|
|
}; |
190
|
|
|
|
|
|
|
|
191
|
|
|
|
|
|
|
my $_find; $_find = sub { |
192
|
|
|
|
|
|
|
my ($self, $files, $dirs, $level) = @_; my (@all, $io); |
193
|
|
|
|
|
|
|
|
194
|
|
|
|
|
|
|
my $filter = $self->_filter; my $follow = not $self->_no_follow; |
195
|
|
|
|
|
|
|
|
196
|
|
|
|
|
|
|
defined $level or $level = $self->_deep ? 0 : 1; |
197
|
|
|
|
|
|
|
|
198
|
|
|
|
|
|
|
while ($io = $self->next) { |
199
|
|
|
|
|
|
|
my $is_dir = $io->is_dir; defined $is_dir or next; |
200
|
|
|
|
|
|
|
|
201
|
|
|
|
|
|
|
(($files and not $is_dir) or ($dirs and $is_dir)) |
202
|
|
|
|
|
|
|
and $_should_include_path->( $filter, $io ) and push @all, $io; |
203
|
|
|
|
|
|
|
|
204
|
|
|
|
|
|
|
$is_dir and ($follow or not $io->is_link) and $level != 1 |
205
|
|
|
|
|
|
|
and push @all, $io->$_find( $files, $dirs, $level ? $level - 1 : 0 ); |
206
|
|
|
|
|
|
|
} |
207
|
|
|
|
|
|
|
|
208
|
|
|
|
|
|
|
not $self->sort and return @all; |
209
|
|
|
|
|
|
|
|
210
|
|
|
|
|
|
|
return $self->reverse ? sort { $b->name cmp $a->name } @all |
211
|
|
|
|
|
|
|
: sort { $a->name cmp $b->name } @all; |
212
|
|
|
|
|
|
|
}; |
213
|
|
|
|
|
|
|
|
214
|
|
|
|
|
|
|
my $_get_atomic_path = sub { |
215
|
|
|
|
|
|
|
my $self = shift; my $path = $self->filepath; my $file; |
216
|
|
|
|
|
|
|
|
217
|
|
|
|
|
|
|
my $infix = $self->_atomic_infix; my $tid = thread_id; |
218
|
|
|
|
|
|
|
|
219
|
|
|
|
|
|
|
$infix =~ m{ \%P }mx and $infix =~ s{ \%P }{$PID}gmx; |
220
|
|
|
|
|
|
|
$infix =~ m{ \%T }mx and $infix =~ s{ \%T }{$tid}gmx; |
221
|
|
|
|
|
|
|
|
222
|
|
|
|
|
|
|
if ($infix =~ m{ \* }mx) { |
223
|
|
|
|
|
|
|
my $name = $self->filename; ($file = $infix) =~ s{ \* }{$name}mx; |
224
|
|
|
|
|
|
|
} |
225
|
|
|
|
|
|
|
else { $file = $self->filename.$infix } |
226
|
|
|
|
|
|
|
|
227
|
|
|
|
|
|
|
return $path ? $_catfile->( $path, $file ) : $file; |
228
|
|
|
|
|
|
|
}; |
229
|
|
|
|
|
|
|
|
230
|
|
|
|
|
|
|
my $_init = sub { |
231
|
|
|
|
|
|
|
my ($self, $type, $name) = @_; |
232
|
|
|
|
|
|
|
|
233
|
|
|
|
|
|
|
$self->_set_io_handle( undef ); |
234
|
|
|
|
|
|
|
$self->_set_is_open ( FALSE ); |
235
|
|
|
|
|
|
|
$self->_set_name ( $name ) if ($name); |
236
|
|
|
|
|
|
|
$self->_set_mode ( 'r' ); |
237
|
|
|
|
|
|
|
$self->_set_type ( $type ); |
238
|
|
|
|
|
|
|
|
239
|
|
|
|
|
|
|
return $self; |
240
|
|
|
|
|
|
|
}; |
241
|
|
|
|
|
|
|
|
242
|
|
|
|
|
|
|
my $_mkdir_perms = sub { # Take file perms and add execute if read is true |
243
|
|
|
|
|
|
|
my $perms = $_[ 1 ] || $_[ 0 ]->_perms; |
244
|
|
|
|
|
|
|
|
245
|
|
|
|
|
|
|
return (($perms & oct '0444') >> 2) | $perms; |
246
|
|
|
|
|
|
|
}; |
247
|
|
|
|
|
|
|
|
248
|
|
|
|
|
|
|
my $_push_layer = sub { |
249
|
|
|
|
|
|
|
my ($self, $layer) = @_; $layer //= NUL; |
250
|
|
|
|
|
|
|
|
251
|
|
|
|
|
|
|
is_member $layer, $self->_layers and return FALSE; |
252
|
|
|
|
|
|
|
push @{ $self->_layers }, $layer; |
253
|
|
|
|
|
|
|
return TRUE; |
254
|
|
|
|
|
|
|
}; |
255
|
|
|
|
|
|
|
|
256
|
|
|
|
|
|
|
my $_sane_binmode = sub { |
257
|
|
|
|
|
|
|
my ($self, $layer) = @_; |
258
|
|
|
|
|
|
|
|
259
|
|
|
|
|
|
|
blessed $self->io_handle eq 'File::ReadBackwards' and return; |
260
|
|
|
|
|
|
|
|
261
|
2
|
|
|
2
|
|
14
|
return $layer ? CORE::binmode( $self->io_handle, $layer ) |
|
2
|
|
|
|
|
3
|
|
|
2
|
|
|
|
|
13
|
|
262
|
|
|
|
|
|
|
: CORE::binmode( $self->io_handle ); |
263
|
|
|
|
|
|
|
}; |
264
|
|
|
|
|
|
|
|
265
|
|
|
|
|
|
|
my $_throw = sub { |
266
|
|
|
|
|
|
|
my $self = shift; eval { $self->unlock }; throw @_; |
267
|
|
|
|
|
|
|
}; |
268
|
|
|
|
|
|
|
|
269
|
|
|
|
|
|
|
my $_umask_pop = sub { |
270
|
|
|
|
|
|
|
my $self = shift; my $perms = $self->_umask->[ -1 ]; |
271
|
|
|
|
|
|
|
|
272
|
|
|
|
|
|
|
(defined $perms and $perms != NO_UMASK_STACK) or return umask; |
273
|
|
|
|
|
|
|
|
274
|
|
|
|
|
|
|
umask pop @{ $self->_umask }; |
275
|
|
|
|
|
|
|
return $perms; |
276
|
|
|
|
|
|
|
}; |
277
|
|
|
|
|
|
|
|
278
|
|
|
|
|
|
|
my $_umask_push = sub { |
279
|
|
|
|
|
|
|
my ($self, $perms) = @_; $perms or return umask; |
280
|
|
|
|
|
|
|
|
281
|
|
|
|
|
|
|
my $first = $self->_umask->[ 0 ]; |
282
|
|
|
|
|
|
|
|
283
|
|
|
|
|
|
|
defined $first and $first == NO_UMASK_STACK and return umask; |
284
|
|
|
|
|
|
|
|
285
|
|
|
|
|
|
|
$perms ^= oct '0777'; push @{ $self->_umask }, umask $perms; |
286
|
|
|
|
|
|
|
|
287
|
|
|
|
|
|
|
return $perms; |
288
|
|
|
|
|
|
|
}; |
289
|
|
|
|
|
|
|
|
290
|
|
|
|
|
|
|
my $_untainted_perms = sub { |
291
|
|
|
|
|
|
|
my $self = shift; $self->exists or return; |
292
|
|
|
|
|
|
|
my $stat = $self->stat // {}; |
293
|
|
|
|
|
|
|
my $mode = $stat->{mode} // NUL; |
294
|
|
|
|
|
|
|
my $perms = $mode =~ m{ \A (\d+) \z }mx ? $1 : 0; |
295
|
|
|
|
|
|
|
|
296
|
|
|
|
|
|
|
return $perms & oct '07777'; |
297
|
|
|
|
|
|
|
}; |
298
|
|
|
|
|
|
|
|
299
|
|
|
|
|
|
|
my $_assert_open_backwards = sub { |
300
|
|
|
|
|
|
|
my ($self, @args) = @_; $self->is_open and return; |
301
|
|
|
|
|
|
|
|
302
|
|
|
|
|
|
|
ensure_class_loaded 'File::ReadBackwards'; |
303
|
|
|
|
|
|
|
|
304
|
|
|
|
|
|
|
$self->_set_io_handle( File::ReadBackwards->new( $self->name, @args ) ) |
305
|
|
|
|
|
|
|
or $self->$_throw( 'File [_1] cannot open backwards: [_2]', |
306
|
|
|
|
|
|
|
[ $self->name, $OS_ERROR ] ); |
307
|
|
|
|
|
|
|
$self->_set_is_open( TRUE ); |
308
|
|
|
|
|
|
|
$self->_set_mode( 'r' ); |
309
|
|
|
|
|
|
|
$self->set_lock; |
310
|
|
|
|
|
|
|
$self->set_binmode; |
311
|
|
|
|
|
|
|
return; |
312
|
|
|
|
|
|
|
}; |
313
|
|
|
|
|
|
|
|
314
|
|
|
|
|
|
|
my $_init_type_from_fs = sub { |
315
|
|
|
|
|
|
|
my $self = shift; |
316
|
|
|
|
|
|
|
|
317
|
|
|
|
|
|
|
CORE::length $self->name or $self->$_throw( Unspecified, [ 'path name' ] ); |
318
|
|
|
|
|
|
|
|
319
|
|
|
|
|
|
|
return -f $self->name ? $self->file : -d _ ? $self->dir : undef; |
320
|
|
|
|
|
|
|
}; |
321
|
|
|
|
|
|
|
|
322
|
|
|
|
|
|
|
my $_open_args = sub { |
323
|
|
|
|
|
|
|
my ($self, $mode, $perms) = @_; |
324
|
|
|
|
|
|
|
|
325
|
|
|
|
|
|
|
CORE::length $self->name or $self->$_throw( Unspecified, [ 'path name' ] ); |
326
|
|
|
|
|
|
|
|
327
|
|
|
|
|
|
|
my $pathname = $self->_atomic && !$self->is_reading( $mode ) |
328
|
|
|
|
|
|
|
? $self->$_get_atomic_path : $self->name; |
329
|
|
|
|
|
|
|
|
330
|
|
|
|
|
|
|
$perms = $self->$_untainted_perms || $perms || $self->_perms; |
331
|
|
|
|
|
|
|
|
332
|
|
|
|
|
|
|
return ($pathname, $self->_set_mode( $mode ), $self->_set__perms( $perms )); |
333
|
|
|
|
|
|
|
}; |
334
|
|
|
|
|
|
|
|
335
|
|
|
|
|
|
|
my $_open_dir = sub { |
336
|
|
|
|
|
|
|
my ($self, $path) = @_; |
337
|
|
|
|
|
|
|
|
338
|
|
|
|
|
|
|
$self->_assert and $self->assert_dirpath( $path ); |
339
|
|
|
|
|
|
|
$self->_set_io_handle( IO::Dir->new( $path ) ) |
340
|
|
|
|
|
|
|
or $self->$_throw( 'Directory [_1] cannot open', [ $path ] ); |
341
|
|
|
|
|
|
|
$self->_set_is_open( TRUE ); |
342
|
|
|
|
|
|
|
return $self; |
343
|
|
|
|
|
|
|
}; |
344
|
|
|
|
|
|
|
|
345
|
|
|
|
|
|
|
my $_open_file = sub { |
346
|
|
|
|
|
|
|
my ($self, $path, $mode, $perms) = @_; |
347
|
|
|
|
|
|
|
|
348
|
|
|
|
|
|
|
$self->_assert and $self->assert_filepath; $self->$_umask_push( $perms ); |
349
|
|
|
|
|
|
|
|
350
|
|
|
|
|
|
|
unless ($self->_set_io_handle( IO::File->new( $path, $mode ) )) { |
351
|
|
|
|
|
|
|
$self->$_umask_pop; |
352
|
|
|
|
|
|
|
$self->$_throw( 'File [_1] cannot open', [ $path ] ); |
353
|
|
|
|
|
|
|
} |
354
|
|
|
|
|
|
|
|
355
|
|
|
|
|
|
|
$self->$_umask_pop; |
356
|
|
|
|
|
|
|
# TODO: Not necessary on normal systems |
357
|
|
|
|
|
|
|
$self->is_writing and CORE::chmod $perms, $path; |
358
|
|
|
|
|
|
|
$self->_set_is_open( TRUE ); |
359
|
|
|
|
|
|
|
$self->set_lock; |
360
|
|
|
|
|
|
|
$self->set_binmode; |
361
|
|
|
|
|
|
|
return $self; |
362
|
|
|
|
|
|
|
}; |
363
|
|
|
|
|
|
|
|
364
|
|
|
|
|
|
|
my $_print = sub { |
365
|
|
|
|
|
|
|
my ($self, @args) = @_; |
366
|
|
|
|
|
|
|
|
367
|
|
|
|
|
|
|
for (@args) { |
368
|
|
|
|
|
|
|
print {$self->io_handle} $_ |
369
|
|
|
|
|
|
|
or $self->$_throw( 'IO error: [_1]', [ $OS_ERROR ] ); |
370
|
|
|
|
|
|
|
} |
371
|
|
|
|
|
|
|
|
372
|
|
|
|
|
|
|
return $self; |
373
|
|
|
|
|
|
|
}; |
374
|
|
|
|
|
|
|
|
375
|
|
|
|
|
|
|
my $_rename_atomic = sub { |
376
|
|
|
|
|
|
|
my $self = shift; my $path = $self->$_get_atomic_path; -f $path or return; |
377
|
|
|
|
|
|
|
|
378
|
|
|
|
|
|
|
File::Copy::move( $path, $self->name ) and return; |
379
|
|
|
|
|
|
|
|
380
|
|
|
|
|
|
|
is_ntfs or $self->$_throw( 'Path [_1] move to [_2] failed: [_3]', |
381
|
|
|
|
|
|
|
[ $path, $self->name, $OS_ERROR ] ); |
382
|
|
|
|
|
|
|
|
383
|
|
|
|
|
|
|
# Try this instead on ntfs |
384
|
|
|
|
|
|
|
warn 'NTFS: Path '.$self->name." move failure: ${OS_ERROR}\n"; |
385
|
|
|
|
|
|
|
eval { unlink $self->name }; my $os_error; |
386
|
|
|
|
|
|
|
File::Copy::copy( $path, $self->name ) or $os_error = $OS_ERROR; |
387
|
|
|
|
|
|
|
eval { unlink $path }; |
388
|
|
|
|
|
|
|
$os_error and $self->$_throw( 'Path [_1] copy to [_2] failed: [_3]', |
389
|
|
|
|
|
|
|
[ $path, $self->name, $os_error ] ); |
390
|
|
|
|
|
|
|
return; |
391
|
|
|
|
|
|
|
}; |
392
|
|
|
|
|
|
|
|
393
|
|
|
|
|
|
|
my $_close_and_rename = sub { # This creates a race condition |
394
|
|
|
|
|
|
|
# uncoverable subroutine |
395
|
|
|
|
|
|
|
my $self = shift; # uncoverable statement |
396
|
|
|
|
|
|
|
|
397
|
|
|
|
|
|
|
my $handle; $self->unlock; |
398
|
|
|
|
|
|
|
|
399
|
|
|
|
|
|
|
if ($handle = $self->io_handle) { $handle->close; delete $self->{io_handle} } |
400
|
|
|
|
|
|
|
|
401
|
|
|
|
|
|
|
$self->_atomic and $self->$_rename_atomic; |
402
|
|
|
|
|
|
|
|
403
|
|
|
|
|
|
|
return $self; |
404
|
|
|
|
|
|
|
}; |
405
|
|
|
|
|
|
|
|
406
|
|
|
|
|
|
|
my $_getline_backwards = sub { |
407
|
|
|
|
|
|
|
my ($self, @args) = @_; $self->$_assert_open_backwards( @args ); |
408
|
|
|
|
|
|
|
|
409
|
|
|
|
|
|
|
return $self->io_handle->readline; |
410
|
|
|
|
|
|
|
}; |
411
|
|
|
|
|
|
|
|
412
|
|
|
|
|
|
|
my $_println = sub { |
413
|
|
|
|
|
|
|
return shift->$_print( map { m{ [\n] \z }mx ? ($_) : ($_, "\n") } @_ ); |
414
|
|
|
|
|
|
|
}; |
415
|
|
|
|
|
|
|
|
416
|
|
|
|
|
|
|
my $_rename_and_close = sub { # This does not create a race condition |
417
|
|
|
|
|
|
|
my $self = shift; my $handle; |
418
|
|
|
|
|
|
|
|
419
|
|
|
|
|
|
|
$self->_atomic and $self->$_rename_atomic; $self->unlock; |
420
|
|
|
|
|
|
|
|
421
|
|
|
|
|
|
|
if ($handle = $self->io_handle) { $handle->close; delete $self->{io_handle} } |
422
|
|
|
|
|
|
|
|
423
|
|
|
|
|
|
|
return $self; |
424
|
|
|
|
|
|
|
}; |
425
|
|
|
|
|
|
|
|
426
|
|
|
|
|
|
|
my $_getlines_backwards = sub { |
427
|
|
|
|
|
|
|
my $self = shift; my (@lines, $line); |
428
|
|
|
|
|
|
|
|
429
|
|
|
|
|
|
|
while (defined ($line = $self->$_getline_backwards)) { push @lines, $line } |
430
|
|
|
|
|
|
|
|
431
|
|
|
|
|
|
|
return @lines; |
432
|
|
|
|
|
|
|
}; |
433
|
|
|
|
|
|
|
|
434
|
|
|
|
|
|
|
# Public methods |
435
|
|
|
|
|
|
|
sub abs2rel { |
436
|
48
|
|
|
48
|
1
|
701
|
return File::Spec->abs2rel( $_[ 0 ]->name, $_[ 1 ] ); |
437
|
|
|
|
|
|
|
} |
438
|
|
|
|
|
|
|
|
439
|
|
|
|
|
|
|
sub absolute { |
440
|
4
|
100
|
|
4
|
1
|
4
|
my ($self, $base) = @_; $base and $base = $_coerce_name->( $base ); |
|
4
|
|
|
|
|
12
|
|
441
|
|
|
|
|
|
|
|
442
|
4
|
100
|
|
|
|
50
|
$self->_set_name |
443
|
|
|
|
|
|
|
( (CORE::length $self->name) ? $self->rel2abs( $base ) : $base ); |
444
|
4
|
|
|
|
|
138
|
return $self; |
445
|
|
|
|
|
|
|
} |
446
|
|
|
|
|
|
|
|
447
|
|
|
|
|
|
|
sub all { |
448
|
69
|
|
|
69
|
1
|
211
|
my ($self, $level) = @_; |
449
|
|
|
|
|
|
|
|
450
|
69
|
100
|
|
|
|
133
|
$self->is_dir and return $self->$_find( TRUE, TRUE, $level ); |
451
|
|
|
|
|
|
|
|
452
|
59
|
|
|
|
|
180
|
return $self->$_all_file_contents; |
453
|
|
|
|
|
|
|
} |
454
|
|
|
|
|
|
|
|
455
|
|
|
|
|
|
|
sub all_dirs { |
456
|
10
|
|
|
10
|
1
|
32
|
return $_[ 0 ]->$_find( FALSE, TRUE, $_[ 1 ] ); |
457
|
|
|
|
|
|
|
} |
458
|
|
|
|
|
|
|
|
459
|
|
|
|
|
|
|
sub all_files { |
460
|
8
|
|
|
8
|
1
|
24
|
return $_[ 0 ]->$_find( TRUE, FALSE, $_[ 1 ] ); |
461
|
|
|
|
|
|
|
} |
462
|
|
|
|
|
|
|
|
463
|
|
|
|
|
|
|
sub append { |
464
|
3
|
|
|
3
|
1
|
24
|
my ($self, @args) = @_; |
465
|
|
|
|
|
|
|
|
466
|
3
|
100
|
100
|
|
|
14
|
if ($self->is_open and not $self->is_reading) { $self->seek( 0, SEEK_END ) } |
|
1
|
|
|
|
|
3
|
|
467
|
2
|
|
|
|
|
4
|
else { $self->assert_open( 'a' ) } |
468
|
|
|
|
|
|
|
|
469
|
3
|
|
|
|
|
10
|
return $self->$_print( @args ); |
470
|
|
|
|
|
|
|
} |
471
|
|
|
|
|
|
|
|
472
|
|
|
|
|
|
|
sub appendln { |
473
|
3
|
|
|
3
|
1
|
7
|
my ($self, @args) = @_; |
474
|
|
|
|
|
|
|
|
475
|
3
|
100
|
100
|
|
|
14
|
if ($self->is_open and not $self->is_reading) { $self->seek( 0, SEEK_END ) } |
|
1
|
|
|
|
|
3
|
|
476
|
2
|
|
|
|
|
5
|
else { $self->assert_open( 'a' ) } |
477
|
|
|
|
|
|
|
|
478
|
3
|
|
|
|
|
11
|
return $self->$_println( @args ); |
479
|
|
|
|
|
|
|
} |
480
|
|
|
|
|
|
|
|
481
|
|
|
|
|
|
|
sub as_boolean { |
482
|
1912
|
100
|
100
|
1912
|
1
|
22947
|
return ((CORE::length $_[ 0 ]->name) || $_[ 0 ]->io_handle) ? TRUE : FALSE; |
483
|
|
|
|
|
|
|
} |
484
|
|
|
|
|
|
|
|
485
|
|
|
|
|
|
|
sub as_string { |
486
|
1019
|
100
|
|
1019
|
1
|
838
|
my $self = shift; CORE::length $self->name and return $self->name; |
|
1019
|
|
|
|
|
12763
|
|
487
|
|
|
|
|
|
|
|
488
|
1
|
50
|
|
|
|
15
|
return defined $self->io_handle ? $self->io_handle.NUL : NUL; |
489
|
|
|
|
|
|
|
} |
490
|
|
|
|
|
|
|
|
491
|
|
|
|
|
|
|
sub assert { |
492
|
3
|
|
|
3
|
1
|
2805
|
my ($self, $cb) = @_; |
493
|
|
|
|
|
|
|
|
494
|
3
|
100
|
|
|
|
6
|
if ($cb) { |
495
|
2
|
|
|
|
|
3
|
local $_ = $self; |
496
|
2
|
100
|
|
|
|
5
|
$cb->() or throw 'Path [_1] assertion failure', [ $self->name ]; |
497
|
|
|
|
|
|
|
} |
498
|
1
|
|
|
|
|
16
|
else { $self->_assert( TRUE ) } |
499
|
|
|
|
|
|
|
|
500
|
2
|
|
|
|
|
59
|
return $self; |
501
|
|
|
|
|
|
|
} |
502
|
|
|
|
|
|
|
|
503
|
|
|
|
|
|
|
sub assert_dirpath { |
504
|
8
|
|
|
8
|
1
|
11
|
my ($self, $dir_name) = @_; |
505
|
|
|
|
|
|
|
|
506
|
8
|
100
|
|
|
|
15
|
$dir_name or return; -d $dir_name and return $dir_name; |
|
5
|
100
|
|
|
|
65
|
|
507
|
|
|
|
|
|
|
|
508
|
4
|
|
|
|
|
8
|
my $perms = $self->$_mkdir_perms; $self->$_umask_push( oct '07777' ); |
|
4
|
|
|
|
|
8
|
|
509
|
|
|
|
|
|
|
|
510
|
4
|
100
|
|
|
|
80
|
unless (CORE::mkdir( $dir_name, $perms )) { |
511
|
2
|
|
|
|
|
6
|
ensure_class_loaded 'File::Path'; |
512
|
2
|
|
|
|
|
508
|
File::Path::make_path( $dir_name, { mode => $perms } ); |
513
|
|
|
|
|
|
|
} |
514
|
|
|
|
|
|
|
|
515
|
3
|
|
|
|
|
12
|
$self->$_umask_pop; |
516
|
|
|
|
|
|
|
|
517
|
|
|
|
|
|
|
# uncoverable branch true |
518
|
3
|
50
|
|
|
|
28
|
-d $dir_name or $self->$_throw( 'Path [_1] cannot create: [_2]', |
519
|
|
|
|
|
|
|
[ $dir_name, $OS_ERROR ] ); |
520
|
3
|
|
|
|
|
4
|
return $dir_name; |
521
|
|
|
|
|
|
|
} |
522
|
|
|
|
|
|
|
|
523
|
|
|
|
|
|
|
sub assert_filepath { |
524
|
7
|
|
|
7
|
1
|
17
|
my $self = shift; my $dir; |
|
7
|
|
|
|
|
8
|
|
525
|
|
|
|
|
|
|
|
526
|
7
|
100
|
|
|
|
85
|
CORE::length $self->name or $self->$_throw( Unspecified, [ 'path name' ] ); |
527
|
|
|
|
|
|
|
|
528
|
6
|
|
|
|
|
94
|
(undef, $dir) = File::Spec->splitpath( $self->name ); |
529
|
|
|
|
|
|
|
|
530
|
6
|
|
|
|
|
64
|
$self->assert_dirpath( $dir ); |
531
|
6
|
|
|
|
|
13
|
return $self; |
532
|
|
|
|
|
|
|
} |
533
|
|
|
|
|
|
|
|
534
|
|
|
|
|
|
|
sub assert_open { |
535
|
667
|
|
100
|
667
|
1
|
2757
|
return $_[ 0 ]->open( $_[ 1 ] // 'r', $_[ 2 ] ); |
536
|
|
|
|
|
|
|
} |
537
|
|
|
|
|
|
|
|
538
|
|
|
|
|
|
|
sub atomic { |
539
|
34
|
|
|
34
|
1
|
560
|
$_[ 0 ]->_atomic( TRUE ); return $_[ 0 ]; |
|
34
|
|
|
|
|
668
|
|
540
|
|
|
|
|
|
|
} |
541
|
|
|
|
|
|
|
|
542
|
|
|
|
|
|
|
sub atomic_infix { |
543
|
2
|
100
|
|
2
|
1
|
18
|
defined $_[ 1 ] and $_[ 0 ]->_atomic_infix( $_[ 1 ] ); return $_[ 0 ]; |
|
2
|
|
|
|
|
37
|
|
544
|
|
|
|
|
|
|
} |
545
|
|
|
|
|
|
|
|
546
|
|
|
|
|
|
|
sub atomic_suffix { |
547
|
2
|
100
|
|
2
|
1
|
421
|
defined $_[ 1 ] and $_[ 0 ]->_atomic_infix( $_[ 1 ] ); return $_[ 0 ]; |
|
2
|
|
|
|
|
32
|
|
548
|
|
|
|
|
|
|
} |
549
|
|
|
|
|
|
|
|
550
|
|
|
|
|
|
|
sub backwards { |
551
|
2
|
|
|
2
|
1
|
30
|
$_[ 0 ]->_backwards( TRUE ); return $_[ 0 ]; |
|
2
|
|
|
|
|
37
|
|
552
|
|
|
|
|
|
|
} |
553
|
|
|
|
|
|
|
|
554
|
|
|
|
|
|
|
sub basename { |
555
|
2
|
100
|
|
2
|
1
|
5
|
my ($self, @suffixes) = @_; CORE::length $self->name or return; |
|
2
|
|
|
|
|
26
|
|
556
|
|
|
|
|
|
|
|
557
|
1
|
|
|
|
|
17
|
return File::Basename::basename( $self->name, @suffixes ); |
558
|
|
|
|
|
|
|
} |
559
|
|
|
|
|
|
|
|
560
|
|
|
|
|
|
|
sub binary { |
561
|
3
|
|
|
3
|
1
|
23
|
my $self = shift; |
562
|
|
|
|
|
|
|
|
563
|
3
|
100
|
100
|
|
|
7
|
$self->$_push_layer( ':raw' ) and $self->is_open and $self->$_sane_binmode; |
564
|
|
|
|
|
|
|
|
565
|
3
|
|
|
|
|
9
|
return $self; |
566
|
|
|
|
|
|
|
} |
567
|
|
|
|
|
|
|
|
568
|
|
|
|
|
|
|
sub binmode { |
569
|
7
|
|
|
7
|
1
|
10
|
my ($self, $layer) = @_; |
570
|
|
|
|
|
|
|
|
571
|
7
|
100
|
100
|
|
|
11
|
$self->$_push_layer( $layer ) |
572
|
|
|
|
|
|
|
and $self->is_open and $self->$_sane_binmode( $layer ); |
573
|
|
|
|
|
|
|
|
574
|
7
|
|
|
|
|
15
|
return $self; |
575
|
|
|
|
|
|
|
} |
576
|
|
|
|
|
|
|
|
577
|
|
|
|
|
|
|
sub block_size { |
578
|
4
|
100
|
|
4
|
1
|
57
|
defined $_[ 1 ] and $_[ 0 ]->_block_size( $_[ 1 ] ); return $_[ 0 ]; |
|
4
|
|
|
|
|
99
|
|
579
|
|
|
|
|
|
|
} |
580
|
|
|
|
|
|
|
|
581
|
|
|
|
|
|
|
sub buffer { |
582
|
163
|
|
|
163
|
1
|
105
|
my $self = shift; |
583
|
|
|
|
|
|
|
|
584
|
163
|
100
|
|
|
|
198
|
if (@_) { |
585
|
2
|
100
|
|
|
|
6
|
my $buffer_ref = ref $_[ 0 ] ? $_[ 0 ] : \$_[ 0 ]; |
586
|
|
|
|
|
|
|
|
587
|
2
|
100
|
|
|
|
2
|
defined ${ $buffer_ref } or ${ $buffer_ref } = NUL; |
|
1
|
|
|
|
|
2
|
|
|
2
|
|
|
|
|
5
|
|
588
|
2
|
|
|
|
|
3
|
$self->{buffer} = $buffer_ref; |
589
|
2
|
|
|
|
|
3
|
return $self; |
590
|
|
|
|
|
|
|
} |
591
|
|
|
|
|
|
|
|
592
|
161
|
100
|
|
|
|
197
|
exists $self->{buffer} or $self->{buffer} = do { my $x = NUL; \$x }; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
2
|
|
593
|
|
|
|
|
|
|
|
594
|
161
|
|
|
|
|
732
|
return $self->{buffer}; |
595
|
|
|
|
|
|
|
} |
596
|
|
|
|
|
|
|
|
597
|
|
|
|
|
|
|
sub canonpath { |
598
|
2
|
|
|
2
|
1
|
27
|
return File::Spec->canonpath( $_[ 0 ]->name ); |
599
|
|
|
|
|
|
|
} |
600
|
|
|
|
|
|
|
|
601
|
|
|
|
|
|
|
sub catdir { |
602
|
3
|
|
|
3
|
1
|
4
|
my ($self, @args) = @_; return $self->child( @args )->dir; |
|
3
|
|
|
|
|
7
|
|
603
|
|
|
|
|
|
|
} |
604
|
|
|
|
|
|
|
|
605
|
|
|
|
|
|
|
sub catfile { |
606
|
5
|
|
|
5
|
1
|
7
|
my ($self, @args) = @_; return $self->child( @args )->file; |
|
5
|
|
|
|
|
18
|
|
607
|
|
|
|
|
|
|
} |
608
|
|
|
|
|
|
|
|
609
|
|
|
|
|
|
|
sub child { |
610
|
10
|
|
|
10
|
1
|
13
|
my ($self, @args) = @_; |
611
|
|
|
|
|
|
|
|
612
|
10
|
100
|
|
|
|
24
|
my $params = (is_hashref $args[ -1 ]) ? pop @args : {}; |
613
|
10
|
100
|
|
|
|
138
|
my $args = [ grep { defined and CORE::length } $self->name, @args ]; |
|
26
|
|
|
|
|
110
|
|
614
|
|
|
|
|
|
|
|
615
|
10
|
|
|
|
|
23
|
return $self->$_constructor( $args, $params ); |
616
|
|
|
|
|
|
|
} |
617
|
|
|
|
|
|
|
|
618
|
|
|
|
|
|
|
sub chmod { |
619
|
4
|
|
|
4
|
1
|
1215
|
my ($self, $perms) = @_; |
620
|
|
|
|
|
|
|
|
621
|
4
|
|
100
|
|
|
17
|
$perms //= $self->_perms; # uncoverable condition false |
622
|
4
|
|
|
|
|
71
|
CORE::chmod $perms, $self->name; |
623
|
4
|
|
|
|
|
96
|
return $self; |
624
|
|
|
|
|
|
|
} |
625
|
|
|
|
|
|
|
|
626
|
|
|
|
|
|
|
sub chomp { |
627
|
5
|
|
|
5
|
1
|
110
|
$_[ 0 ]->_chomp( TRUE ); return $_[ 0 ]; |
|
5
|
|
|
|
|
106
|
|
628
|
|
|
|
|
|
|
} |
629
|
|
|
|
|
|
|
|
630
|
|
|
|
|
|
|
sub chown { |
631
|
4
|
|
|
4
|
1
|
4281
|
my ($self, $uid, $gid) = @_; |
632
|
|
|
|
|
|
|
|
633
|
4
|
100
|
100
|
|
|
28
|
(defined $uid and defined $gid) |
634
|
|
|
|
|
|
|
or $self->$_throw( Unspecified, [ 'user or group id' ] ); |
635
|
|
|
|
|
|
|
|
636
|
2
|
50
|
|
|
|
44
|
1 == CORE::chown $uid, $gid, $self->name |
637
|
|
|
|
|
|
|
or $self->$_throw( 'Path [_1 chown failed to [_2]/[_3]', |
638
|
|
|
|
|
|
|
[ $self->name, $uid, $gid ] ); |
639
|
2
|
|
|
|
|
77
|
return $self; |
640
|
|
|
|
|
|
|
} |
641
|
|
|
|
|
|
|
|
642
|
|
|
|
|
|
|
sub clear { |
643
|
35
|
|
|
35
|
1
|
32
|
${ $_[ 0 ]->buffer } = NUL; return $_[ 0 ]; |
|
35
|
|
|
|
|
44
|
|
|
35
|
|
|
|
|
40
|
|
644
|
|
|
|
|
|
|
} |
645
|
|
|
|
|
|
|
|
646
|
|
|
|
|
|
|
sub close { |
647
|
892
|
100
|
|
892
|
1
|
7003
|
my $self = shift; $self->is_open or return $self; |
|
892
|
|
|
|
|
2008
|
|
648
|
|
|
|
|
|
|
|
649
|
273
|
50
|
|
|
|
577
|
if (is_ntfs) { # uncoverable branch true |
650
|
0
|
|
|
|
|
0
|
$self->$_close_and_rename; # uncoverable statement |
651
|
273
|
|
|
|
|
442
|
} else { $self->$_rename_and_close } |
652
|
|
|
|
|
|
|
|
653
|
273
|
|
|
|
|
6875
|
$self->_set_io_handle( undef ); |
654
|
273
|
|
|
|
|
6973
|
$self->_set_is_open ( FALSE ); |
655
|
273
|
|
|
|
|
6560
|
$self->_set_mode ( 'r' ); |
656
|
273
|
|
|
|
|
3541
|
return $self; |
657
|
|
|
|
|
|
|
} |
658
|
|
|
|
|
|
|
|
659
|
|
|
|
|
|
|
sub copy { |
660
|
4
|
|
|
4
|
1
|
64
|
my ($self, $to) = @_; |
661
|
|
|
|
|
|
|
|
662
|
4
|
50
|
|
|
|
14
|
$to or $self->$_throw( Unspecified, [ 'copy to' ] ); |
663
|
|
|
|
|
|
|
|
664
|
4
|
100
|
100
|
|
|
64
|
(blessed $to and $to->isa( __PACKAGE__ )) |
665
|
|
|
|
|
|
|
or $to = $self->$_constructor( $to ); |
666
|
|
|
|
|
|
|
|
667
|
4
|
50
|
|
|
|
51
|
File::Copy::copy( $self->name, $to->pathname ) |
668
|
|
|
|
|
|
|
or $self->$_throw( 'Cannot copy [_1] to [_2]', |
669
|
|
|
|
|
|
|
[ $self->name, $to->pathname ] ); |
670
|
|
|
|
|
|
|
|
671
|
4
|
|
|
|
|
1001
|
return $to; |
672
|
|
|
|
|
|
|
} |
673
|
|
|
|
|
|
|
|
674
|
|
|
|
|
|
|
sub cwd { |
675
|
1
|
|
|
1
|
1
|
1
|
my $self = shift; return $self->$_constructor( Cwd::getcwd(), @_ ); |
|
1
|
|
|
|
|
10
|
|
676
|
|
|
|
|
|
|
} |
677
|
|
|
|
|
|
|
|
678
|
|
|
|
|
|
|
sub deep { |
679
|
10
|
|
|
10
|
1
|
156
|
$_[ 0 ]->_deep( TRUE ); return $_[ 0 ]; |
|
10
|
|
|
|
|
230
|
|
680
|
|
|
|
|
|
|
} |
681
|
|
|
|
|
|
|
|
682
|
|
|
|
|
|
|
sub delete { |
683
|
21
|
|
|
21
|
1
|
113
|
my $self = shift; my $path = $self->$_get_atomic_path; |
|
21
|
|
|
|
|
45
|
|
684
|
|
|
|
|
|
|
|
685
|
21
|
100
|
100
|
|
|
290
|
$self->_atomic and -f $path and unlink $path; |
686
|
|
|
|
|
|
|
|
687
|
21
|
|
|
|
|
461
|
return $self->close; |
688
|
|
|
|
|
|
|
} |
689
|
|
|
|
|
|
|
|
690
|
|
|
|
|
|
|
sub delete_tmp_files { |
691
|
2
|
|
100
|
2
|
1
|
526
|
my ($self, $tmplt) = @_; $tmplt //= '%6.6d....'; |
|
2
|
|
|
|
|
13
|
|
692
|
|
|
|
|
|
|
|
693
|
2
|
|
|
|
|
15
|
my $pat = sprintf $tmplt, $PID; |
694
|
|
|
|
|
|
|
|
695
|
2
|
|
|
|
|
6
|
while (my $entry = $self->next) { |
696
|
48
|
50
|
|
|
|
240
|
$entry->filename =~ m{ \A $pat \z }mx and unlink $entry->pathname; |
697
|
|
|
|
|
|
|
} |
698
|
|
|
|
|
|
|
|
699
|
2
|
|
|
|
|
7
|
return $self->close; |
700
|
|
|
|
|
|
|
} |
701
|
|
|
|
|
|
|
|
702
|
|
|
|
|
|
|
sub digest { # Robbed from Path::Tiny |
703
|
4
|
|
|
4
|
1
|
6
|
my ($self, @args) = @_; my $n = 0; $n++ while (defined $args[ $n ]); |
|
4
|
|
|
|
|
6
|
|
|
4
|
|
|
|
|
13
|
|
704
|
|
|
|
|
|
|
|
705
|
|
|
|
|
|
|
my $args = ( $n == 0) ? { algorithm => 'SHA-256' } |
706
|
|
|
|
|
|
|
: (is_hashref $args[ 0 ]) ? { algorithm => 'SHA-256', |
707
|
1
|
|
|
|
|
4
|
%{ $args[ 0 ] } } |
708
|
|
|
|
|
|
|
: ( $n == 1) ? { algorithm => $args[ 0 ] } |
709
|
|
|
|
|
|
|
: { algorithm => $args[ 0 ], |
710
|
4
|
100
|
|
|
|
15
|
%{ $args[ 1 ] } }; |
|
1
|
100
|
|
|
|
4
|
|
|
|
100
|
|
|
|
|
|
711
|
|
|
|
|
|
|
|
712
|
4
|
|
|
|
|
11
|
ensure_class_loaded 'Digest'; my $digest = Digest->new( $args->{algorithm} ); |
|
4
|
|
|
|
|
79
|
|
713
|
|
|
|
|
|
|
|
714
|
4
|
100
|
|
|
|
3290
|
if ($args->{block_size}) { |
715
|
2
|
|
|
|
|
5
|
$self->binmode( ':unix' )->lock->block_size( $args->{block_size} ); |
716
|
|
|
|
|
|
|
|
717
|
2
|
|
|
|
|
4
|
while ($self->read) { $digest->add( ${ $self->buffer } ); $self->clear; } |
|
20
|
|
|
|
|
12
|
|
|
20
|
|
|
|
|
22
|
|
|
20
|
|
|
|
|
25
|
|
718
|
|
|
|
|
|
|
} |
719
|
2
|
|
|
|
|
6
|
else { $digest->add( $self->binmode( ':unix' )->lock->all ) } |
720
|
|
|
|
|
|
|
|
721
|
4
|
|
|
|
|
58
|
return $digest; |
722
|
|
|
|
|
|
|
} |
723
|
|
|
|
|
|
|
|
724
|
|
|
|
|
|
|
sub dir { |
725
|
172
|
|
|
172
|
1
|
2524
|
return shift->$_init( 'dir', @_ ); |
726
|
|
|
|
|
|
|
} |
727
|
|
|
|
|
|
|
|
728
|
|
|
|
|
|
|
sub dirname { |
729
|
5
|
50
|
|
5
|
1
|
63
|
return CORE::length $_[ 0 ]->name ? File::Basename::dirname( $_[ 0 ]->name ) |
730
|
|
|
|
|
|
|
: NUL; |
731
|
|
|
|
|
|
|
} |
732
|
|
|
|
|
|
|
|
733
|
|
|
|
|
|
|
sub encoding { |
734
|
4
|
|
|
4
|
1
|
9
|
my ($self, $encoding) = @_; |
735
|
|
|
|
|
|
|
|
736
|
4
|
100
|
|
|
|
16
|
$encoding or $self->$_throw( Unspecified, [ 'encoding value' ] ); |
737
|
3
|
50
|
33
|
|
|
14
|
$self->$_push_layer( ":encoding($encoding)" ) |
738
|
|
|
|
|
|
|
and $self->is_open and $self->$_sane_binmode( ":encoding($encoding)" ); |
739
|
3
|
|
|
|
|
6
|
return $self; |
740
|
|
|
|
|
|
|
} |
741
|
|
|
|
|
|
|
|
742
|
|
|
|
|
|
|
sub error_check { |
743
|
147
|
|
|
147
|
1
|
148
|
my $self = shift; |
744
|
|
|
|
|
|
|
|
745
|
147
|
50
|
33
|
|
|
1040
|
$self->io_handle->can( 'error' ) |
746
|
|
|
|
|
|
|
and $self->io_handle->error |
747
|
|
|
|
|
|
|
and $self->$_throw( 'IO error: [_1]', [ $OS_ERROR ] ); |
748
|
|
|
|
|
|
|
|
749
|
147
|
|
|
|
|
153
|
return $self; |
750
|
|
|
|
|
|
|
} |
751
|
|
|
|
|
|
|
|
752
|
|
|
|
|
|
|
sub exists { |
753
|
1079
|
100
|
100
|
1079
|
1
|
14052
|
return (CORE::length $_[ 0 ]->name && -e $_[ 0 ]->name) ? TRUE : FALSE; |
754
|
|
|
|
|
|
|
} |
755
|
|
|
|
|
|
|
|
756
|
|
|
|
|
|
|
sub fdopen { |
757
|
1
|
|
|
1
|
1
|
20
|
my ($self, $fd, $mode) = @_; |
758
|
|
|
|
|
|
|
|
759
|
1
|
|
|
|
|
5
|
$self->io_handle->fdopen( $fd, $mode ); |
760
|
1
|
|
|
|
|
321
|
$self->_set_is_open( $self->io_handle->opened ); |
761
|
1
|
|
|
|
|
139
|
$self->_set_mode( $mode ); |
762
|
1
|
|
|
|
|
32
|
$self->_set_name( NUL ); |
763
|
1
|
|
|
|
|
49
|
$self->_set_type( undef ); |
764
|
1
|
|
|
|
|
14
|
return $self; |
765
|
|
|
|
|
|
|
} |
766
|
|
|
|
|
|
|
|
767
|
|
|
|
|
|
|
sub file { |
768
|
240
|
|
|
240
|
1
|
3605
|
return shift->$_init( 'file', @_ ); |
769
|
|
|
|
|
|
|
} |
770
|
|
|
|
|
|
|
|
771
|
|
|
|
|
|
|
sub filename { |
772
|
504
|
|
|
504
|
1
|
487
|
my $self = shift; my $file; |
|
504
|
|
|
|
|
343
|
|
773
|
|
|
|
|
|
|
|
774
|
504
|
|
|
|
|
6500
|
(undef, undef, $file) = File::Spec->splitpath( $self->name ); |
775
|
|
|
|
|
|
|
|
776
|
504
|
|
|
|
|
6401
|
return $file; |
777
|
|
|
|
|
|
|
} |
778
|
|
|
|
|
|
|
|
779
|
|
|
|
|
|
|
sub filepath { |
780
|
111
|
|
|
111
|
1
|
78
|
my $self = shift; my ($volume, $dir) = File::Spec->splitpath( $self->name ); |
|
111
|
|
|
|
|
1355
|
|
781
|
|
|
|
|
|
|
|
782
|
111
|
|
|
|
|
1705
|
return File::Spec->catpath( $volume, $dir, NUL ); |
783
|
|
|
|
|
|
|
} |
784
|
|
|
|
|
|
|
|
785
|
|
|
|
|
|
|
sub filter { |
786
|
33
|
50
|
|
33
|
1
|
874
|
defined $_[ 1 ] and $_[ 0 ]->_filter( $_[ 1 ] ); return $_[ 0 ]; |
|
33
|
|
|
|
|
394
|
|
787
|
|
|
|
|
|
|
} |
788
|
|
|
|
|
|
|
|
789
|
|
|
|
|
|
|
sub getline { |
790
|
19
|
|
|
19
|
1
|
25
|
my ($self, $separator) = @_; |
791
|
|
|
|
|
|
|
|
792
|
19
|
100
|
|
|
|
289
|
$self->_backwards and return $self->$_getline_backwards; |
793
|
|
|
|
|
|
|
|
794
|
18
|
|
|
|
|
114
|
my $line; $self->assert_open; |
|
18
|
|
|
|
|
30
|
|
795
|
|
|
|
|
|
|
|
796
|
18
|
|
66
|
|
|
24
|
{ local $RS = $separator // $self->_separator; # uncoverable condition false |
|
18
|
|
|
|
|
283
|
|
797
|
18
|
|
|
|
|
375
|
$line = $self->io_handle->getline; |
798
|
18
|
50
|
66
|
|
|
730
|
defined $line and $self->_chomp and CORE::chomp $line; |
799
|
|
|
|
|
|
|
} |
800
|
|
|
|
|
|
|
|
801
|
18
|
|
|
|
|
121
|
$self->error_check; |
802
|
18
|
100
|
|
|
|
52
|
defined $line and return $line; |
803
|
1
|
50
|
|
|
|
17
|
$self->autoclose and $self->close; |
804
|
1
|
|
|
|
|
1
|
return; |
805
|
|
|
|
|
|
|
} |
806
|
|
|
|
|
|
|
|
807
|
|
|
|
|
|
|
sub getlines { |
808
|
7
|
|
|
7
|
1
|
606
|
my ($self, $separator) = @_; |
809
|
|
|
|
|
|
|
|
810
|
7
|
100
|
|
|
|
100
|
$self->_backwards and return $self->$_getlines_backwards; |
811
|
|
|
|
|
|
|
|
812
|
6
|
|
|
|
|
27
|
my @lines; $self->assert_open; |
|
6
|
|
|
|
|
11
|
|
813
|
|
|
|
|
|
|
|
814
|
6
|
|
66
|
|
|
9
|
{ local $RS = $separator // $self->_separator; # uncoverable condition false |
|
6
|
|
|
|
|
67
|
|
815
|
6
|
|
|
|
|
146
|
@lines = $self->io_handle->getlines; |
816
|
|
|
|
|
|
|
|
817
|
6
|
100
|
|
|
|
570
|
if ($self->_chomp) { CORE::chomp for @lines } |
|
5
|
|
|
|
|
83
|
|
818
|
|
|
|
|
|
|
} |
819
|
|
|
|
|
|
|
|
820
|
6
|
|
|
|
|
16
|
$self->error_check; |
821
|
6
|
100
|
|
|
|
58
|
scalar @lines and return (@lines); |
822
|
1
|
50
|
|
|
|
15
|
$self->autoclose and $self->close; |
823
|
1
|
|
|
|
|
3
|
return (); |
824
|
|
|
|
|
|
|
} |
825
|
|
|
|
|
|
|
|
826
|
|
|
|
|
|
|
sub head { |
827
|
2
|
|
100
|
2
|
1
|
3
|
my ($self, $lines) = @_; my @res; $lines //= 10; $self->close; |
|
2
|
|
|
|
|
2
|
|
|
2
|
|
|
|
|
9
|
|
|
2
|
|
|
|
|
4
|
|
828
|
|
|
|
|
|
|
|
829
|
2
|
|
|
|
|
5
|
while ($lines--) { |
830
|
13
|
50
|
|
|
|
18
|
defined (my $l = $self->getline) or last; push @res, $l; |
|
13
|
|
|
|
|
27
|
|
831
|
|
|
|
|
|
|
} |
832
|
|
|
|
|
|
|
|
833
|
2
|
|
|
|
|
7
|
$self->close; |
834
|
2
|
50
|
|
|
|
20
|
return wantarray ? @res : join NUL, @res; |
835
|
|
|
|
|
|
|
} |
836
|
|
|
|
|
|
|
|
837
|
|
|
|
|
|
|
sub hexdigest { |
838
|
4
|
|
|
4
|
1
|
11
|
my ($self, @args) = @_; return $self->digest( @args )->hexdigest; |
|
4
|
|
|
|
|
10
|
|
839
|
|
|
|
|
|
|
} |
840
|
|
|
|
|
|
|
|
841
|
|
|
|
|
|
|
sub is_absolute { |
842
|
2
|
|
|
2
|
1
|
28
|
return File::Spec->file_name_is_absolute( $_[ 0 ]->name ); |
843
|
|
|
|
|
|
|
} |
844
|
|
|
|
|
|
|
|
845
|
|
|
|
|
|
|
sub is_dir { |
846
|
674
|
100
|
|
674
|
1
|
2186
|
my $self = shift; CORE::length $self->name or return FALSE; |
|
674
|
|
|
|
|
8676
|
|
847
|
|
|
|
|
|
|
|
848
|
672
|
100
|
100
|
|
|
4163
|
$self->type or $self->$_init_type_from_fs or return FALSE; |
849
|
|
|
|
|
|
|
|
850
|
671
|
100
|
|
|
|
3214
|
return $self->type eq 'dir' ? TRUE : FALSE; |
851
|
|
|
|
|
|
|
} |
852
|
|
|
|
|
|
|
|
853
|
|
|
|
|
|
|
sub is_empty { |
854
|
43
|
|
|
43
|
1
|
53
|
my $self = shift; my $name = $self->name; my $empty; |
|
43
|
|
|
|
|
611
|
|
|
43
|
|
|
|
|
175
|
|
855
|
|
|
|
|
|
|
|
856
|
43
|
100
|
|
|
|
89
|
$self->exists or $self->$_throw( PathNotFound, [ $name ] ); |
857
|
40
|
100
|
|
|
|
1196
|
$self->is_file and return -z $name ? TRUE : FALSE; |
|
|
100
|
|
|
|
|
|
858
|
2
|
50
|
|
|
|
6
|
$empty = $self->next ? FALSE : TRUE; $self->close; |
|
2
|
|
|
|
|
5
|
|
859
|
2
|
|
|
|
|
6
|
return $empty; |
860
|
|
|
|
|
|
|
} |
861
|
|
|
|
|
|
|
|
862
|
|
|
|
|
|
|
*empty = \&is_empty; # Deprecated |
863
|
|
|
|
|
|
|
|
864
|
|
|
|
|
|
|
sub is_executable { |
865
|
3
|
100
|
100
|
3
|
1
|
1299
|
return (CORE::length $_[ 0 ]->name) && -x $_[ 0 ]->name ? TRUE : FALSE; |
866
|
|
|
|
|
|
|
} |
867
|
|
|
|
|
|
|
|
868
|
|
|
|
|
|
|
sub is_file { |
869
|
42
|
100
|
|
42
|
1
|
57
|
my $self = shift; CORE::length $self->name or return FALSE; |
|
42
|
|
|
|
|
553
|
|
870
|
|
|
|
|
|
|
|
871
|
41
|
100
|
100
|
|
|
311
|
$self->type or $self->$_init_type_from_fs or return FALSE; |
872
|
|
|
|
|
|
|
|
873
|
40
|
100
|
|
|
|
533
|
return $self->type eq 'file' ? TRUE : FALSE; |
874
|
|
|
|
|
|
|
} |
875
|
|
|
|
|
|
|
|
876
|
|
|
|
|
|
|
sub is_link { |
877
|
463
|
100
|
100
|
463
|
1
|
6057
|
return (CORE::length $_[ 0 ]->name) && -l $_[ 0 ]->name ? TRUE : FALSE; |
878
|
|
|
|
|
|
|
} |
879
|
|
|
|
|
|
|
|
880
|
|
|
|
|
|
|
sub is_readable { |
881
|
2
|
100
|
66
|
2
|
1
|
38
|
return (CORE::length $_[ 0 ]->name) && -r $_[ 0 ]->name ? TRUE : FALSE; |
882
|
|
|
|
|
|
|
} |
883
|
|
|
|
|
|
|
|
884
|
|
|
|
|
|
|
sub is_reading { |
885
|
96
|
|
66
|
96
|
1
|
537
|
my $mode = $_[ 1 ] // $_[ 0 ]->mode; return first { $_ eq $mode } qw( r r+ ); |
|
61
|
|
|
61
|
|
396
|
|
|
61
|
|
|
|
|
279
|
|
886
|
|
|
|
|
|
|
} |
887
|
|
|
|
|
|
|
|
888
|
|
|
|
|
|
|
sub is_writable { |
889
|
5
|
100
|
66
|
5
|
1
|
220
|
return (CORE::length $_[ 0 ]->name) && -w $_[ 0 ]->name ? TRUE : FALSE; |
890
|
|
|
|
|
|
|
} |
891
|
|
|
|
|
|
|
|
892
|
|
|
|
|
|
|
sub is_writing { |
893
|
140
|
|
66
|
140
|
1
|
607
|
my $mode = $_[ 1 ] // $_[ 0 ]->mode; |
894
|
|
|
|
|
|
|
|
895
|
140
|
|
|
489
|
|
626
|
return first { $_ eq $mode } qw( a a+ w w+ ); |
|
489
|
|
|
|
|
1801
|
|
896
|
|
|
|
|
|
|
} |
897
|
|
|
|
|
|
|
|
898
|
|
|
|
|
|
|
sub iterator { |
899
|
5
|
|
|
5
|
1
|
36
|
my ($self, $args) = @_; |
900
|
|
|
|
|
|
|
|
901
|
5
|
50
|
|
|
|
9
|
$self->is_dir |
902
|
|
|
|
|
|
|
or $self->$_throw( "Path [_1] is not a directory", [ $self->name ] ); |
903
|
|
|
|
|
|
|
|
904
|
5
|
|
|
|
|
13
|
my @dirs = ( $self ); |
905
|
5
|
|
|
|
|
64
|
my $filter = $self->_filter; |
906
|
5
|
|
100
|
|
|
76
|
my $deep = $args->{recurse} // $self->_deep; |
907
|
5
|
|
100
|
|
|
75
|
my $follow = $args->{follow_symlinks} // not $self->_no_follow; |
908
|
|
|
|
|
|
|
|
909
|
|
|
|
|
|
|
return sub { |
910
|
40
|
|
|
40
|
|
544
|
while (@dirs) { |
911
|
51
|
|
|
|
|
292
|
while (defined (my $path = $dirs[ 0 ]->next)) { |
912
|
44
|
100
|
100
|
|
|
105
|
$deep and $path->is_dir and ($follow or not $path->is_link) |
|
|
|
100
|
|
|
|
|
|
|
|
66
|
|
|
|
|
913
|
|
|
|
|
|
|
and unshift @dirs, $path; |
914
|
44
|
100
|
|
|
|
165
|
$_should_include_path->( $filter, $path ) and return $path; |
915
|
|
|
|
|
|
|
} |
916
|
|
|
|
|
|
|
|
917
|
15
|
|
|
|
|
156
|
shift @dirs; |
918
|
|
|
|
|
|
|
} |
919
|
|
|
|
|
|
|
|
920
|
4
|
|
|
|
|
8
|
return; |
921
|
5
|
|
|
|
|
44
|
}; |
922
|
|
|
|
|
|
|
} |
923
|
|
|
|
|
|
|
|
924
|
|
|
|
|
|
|
sub length { |
925
|
53
|
|
|
53
|
1
|
126
|
return CORE::length ${ $_[ 0 ]->buffer }; |
|
53
|
|
|
|
|
61
|
|
926
|
|
|
|
|
|
|
} |
927
|
|
|
|
|
|
|
|
928
|
|
|
|
|
|
|
sub lock { |
929
|
70
|
|
100
|
70
|
1
|
1310
|
$_[ 0 ]->_lock( $_[ 1 ] // LOCK_BLOCKING ); return $_[ 0 ]; |
|
70
|
|
|
|
|
1556
|
|
930
|
|
|
|
|
|
|
} |
931
|
|
|
|
|
|
|
|
932
|
|
|
|
|
|
|
sub mkdir { |
933
|
2
|
|
33
|
2
|
1
|
22
|
my ($self, $perms) = @_; $perms ||= $self->$_mkdir_perms; |
|
2
|
|
|
|
|
10
|
|
934
|
|
|
|
|
|
|
|
935
|
2
|
|
|
|
|
6
|
$self->$_umask_push( oct '07777' ); |
936
|
|
|
|
|
|
|
|
937
|
2
|
|
|
|
|
30
|
CORE::mkdir( $self->name, $perms ); |
938
|
|
|
|
|
|
|
|
939
|
2
|
|
|
|
|
141
|
$self->$_umask_pop; |
940
|
|
|
|
|
|
|
|
941
|
2
|
50
|
|
|
|
36
|
-d $self->name or $self->$_throw( 'Path [_1] cannot create: [_2]', |
942
|
|
|
|
|
|
|
[ $self->name, $OS_ERROR ] ); |
943
|
2
|
|
|
|
|
30
|
return $self; |
944
|
|
|
|
|
|
|
} |
945
|
|
|
|
|
|
|
|
946
|
|
|
|
|
|
|
sub mkpath { |
947
|
1
|
|
33
|
1
|
1
|
2
|
my ($self, $perms) = @_; $perms ||= $self->$_mkdir_perms; |
|
1
|
|
|
|
|
6
|
|
948
|
|
|
|
|
|
|
|
949
|
1
|
|
|
|
|
3
|
$self->$_umask_push( oct '07777' ); ensure_class_loaded 'File::Path'; |
|
1
|
|
|
|
|
5
|
|
950
|
|
|
|
|
|
|
|
951
|
1
|
|
|
|
|
60
|
File::Path::make_path( $self->name, { mode => $perms } ); |
952
|
|
|
|
|
|
|
|
953
|
1
|
|
|
|
|
302
|
$self->$_umask_pop; |
954
|
|
|
|
|
|
|
|
955
|
1
|
50
|
|
|
|
18
|
-d $self->name or $self->$_throw( 'Path [_1] cannot create: [_2]', |
956
|
|
|
|
|
|
|
[ $self->name, $OS_ERROR ] ); |
957
|
1
|
|
|
|
|
16
|
return $self; |
958
|
|
|
|
|
|
|
} |
959
|
|
|
|
|
|
|
|
960
|
|
|
|
|
|
|
sub move { |
961
|
3
|
|
|
3
|
1
|
27
|
my ($self, $to) = @_; |
962
|
|
|
|
|
|
|
|
963
|
3
|
50
|
|
|
|
11
|
$to or $self->$_throw( Unspecified, [ 'move to' ] ); |
964
|
|
|
|
|
|
|
|
965
|
3
|
100
|
100
|
|
|
32
|
(blessed $to and $to->isa( __PACKAGE__ )) |
966
|
|
|
|
|
|
|
or $to = $self->$_constructor( $to ); |
967
|
|
|
|
|
|
|
|
968
|
3
|
50
|
|
|
|
38
|
File::Copy::move( $self->name, $to->pathname ) |
969
|
|
|
|
|
|
|
or $self->$_throw( 'Cannot move [_1] to [_2]', |
970
|
|
|
|
|
|
|
[ $self->name, $to->pathname ] ); |
971
|
|
|
|
|
|
|
|
972
|
3
|
|
|
|
|
203
|
return $to; |
973
|
|
|
|
|
|
|
} |
974
|
|
|
|
|
|
|
|
975
|
|
|
|
|
|
|
sub next { |
976
|
457
|
100
|
|
457
|
1
|
1911
|
my $self = shift; defined (my $name = $self->read_dir) or return; |
|
457
|
|
|
|
|
644
|
|
977
|
|
|
|
|
|
|
|
978
|
333
|
|
|
|
|
4389
|
my $io = $self->$_constructor( [ $self->name, $name ], { |
979
|
|
|
|
|
|
|
reverse => $self->reverse, sort => $self->sort } ); |
980
|
|
|
|
|
|
|
|
981
|
333
|
100
|
|
|
|
4623
|
defined $self->_filter and $io->filter( $self->_filter ); |
982
|
|
|
|
|
|
|
|
983
|
333
|
|
|
|
|
1673
|
return $io; |
984
|
|
|
|
|
|
|
} |
985
|
|
|
|
|
|
|
|
986
|
|
|
|
|
|
|
sub no_follow { |
987
|
2
|
|
|
2
|
1
|
31
|
$_[ 0 ]->_no_follow( TRUE ); return $_[ 0 ]; |
|
2
|
|
|
|
|
40
|
|
988
|
|
|
|
|
|
|
} |
989
|
|
|
|
|
|
|
|
990
|
|
|
|
|
|
|
sub open { |
991
|
669
|
|
66
|
669
|
1
|
1189
|
my ($self, $mode, $perms) = @_; $mode //= $self->mode; |
|
669
|
|
|
|
|
1042
|
|
992
|
|
|
|
|
|
|
|
993
|
669
|
100
|
100
|
|
|
1961
|
$self->is_open |
994
|
|
|
|
|
|
|
and first_char $mode eq first_char $self->mode |
995
|
|
|
|
|
|
|
and return $self; |
996
|
263
|
50
|
100
|
|
|
555
|
$self->is_open |
|
|
|
50
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
|
33
|
|
|
|
|
997
|
|
|
|
|
|
|
and 'r' eq first_char $mode |
998
|
|
|
|
|
|
|
and '+' eq (substr $self->mode, 1, 1) || NUL |
999
|
|
|
|
|
|
|
and $self->seek( 0, SEEK_SET ) |
1000
|
|
|
|
|
|
|
and return $self; |
1001
|
263
|
100
|
|
|
|
548
|
$self->type or $self->$_init_type_from_fs; $self->type or $self->file; |
|
262
|
100
|
|
|
|
833
|
|
1002
|
262
|
100
|
|
|
|
508
|
$self->is_open and $self->close; |
1003
|
|
|
|
|
|
|
|
1004
|
262
|
100
|
|
|
|
401
|
return $self->is_dir |
1005
|
|
|
|
|
|
|
? $self->$_open_dir ( $self->$_open_args( $mode, $perms ) ) |
1006
|
|
|
|
|
|
|
: $self->$_open_file( $self->$_open_args( $mode, $perms ) ); |
1007
|
|
|
|
|
|
|
} |
1008
|
|
|
|
|
|
|
|
1009
|
|
|
|
|
|
|
sub parent { |
1010
|
3
|
|
100
|
3
|
1
|
2
|
my ($self, $count) = @_; my $parent = $self; $count ||= 1; |
|
3
|
|
|
|
|
3
|
|
|
3
|
|
|
|
|
9
|
|
1011
|
|
|
|
|
|
|
|
1012
|
3
|
|
|
|
|
10
|
$parent = $self->$_constructor( $parent->dirname ) while ($count--); |
1013
|
|
|
|
|
|
|
|
1014
|
3
|
|
|
|
|
28
|
return $parent; |
1015
|
|
|
|
|
|
|
} |
1016
|
|
|
|
|
|
|
|
1017
|
|
|
|
|
|
|
sub pathname { |
1018
|
11
|
|
|
11
|
1
|
181
|
return $_[ 0 ]->name; |
1019
|
|
|
|
|
|
|
} |
1020
|
|
|
|
|
|
|
|
1021
|
|
|
|
|
|
|
sub perms { |
1022
|
11
|
50
|
|
11
|
1
|
406
|
defined $_[ 1 ] and $_[ 0 ]->_set__perms( $_[ 1 ] ); return $_[ 0 ]; |
|
11
|
|
|
|
|
349
|
|
1023
|
|
|
|
|
|
|
} |
1024
|
|
|
|
|
|
|
|
1025
|
|
|
|
|
|
|
sub print { |
1026
|
43
|
|
|
43
|
1
|
1356
|
return shift->assert_open( 'w' )->$_print( @_ ); |
1027
|
|
|
|
|
|
|
} |
1028
|
|
|
|
|
|
|
|
1029
|
|
|
|
|
|
|
sub println { |
1030
|
16
|
|
|
16
|
1
|
454
|
return shift->assert_open( 'w' )->$_println( @_ ); |
1031
|
|
|
|
|
|
|
} |
1032
|
|
|
|
|
|
|
|
1033
|
|
|
|
|
|
|
sub read { |
1034
|
38
|
|
|
38
|
1
|
295
|
my ($self, @args) = @_; $self->assert_open; |
|
38
|
|
|
|
|
45
|
|
1035
|
|
|
|
|
|
|
|
1036
|
|
|
|
|
|
|
my $length = @args || $self->is_dir |
1037
|
|
|
|
|
|
|
? $self->io_handle->read( @args ) |
1038
|
38
|
50
|
33
|
|
|
98
|
: $self->io_handle->read( ${ $self->buffer }, |
|
38
|
|
|
|
|
50
|
|
1039
|
|
|
|
|
|
|
$self->_block_size, $self->length ); |
1040
|
|
|
|
|
|
|
|
1041
|
38
|
|
|
|
|
309
|
$self->error_check; |
1042
|
|
|
|
|
|
|
|
1043
|
38
|
|
66
|
|
|
133
|
return $length || $self->autoclose && $self->close && 0; |
1044
|
|
|
|
|
|
|
} |
1045
|
|
|
|
|
|
|
|
1046
|
|
|
|
|
|
|
sub read_dir { |
1047
|
458
|
100
|
|
458
|
1
|
306
|
my $self = shift; $self->type or $self->dir; $self->assert_open; |
|
458
|
|
|
|
|
820
|
|
|
458
|
|
|
|
|
603
|
|
1048
|
|
|
|
|
|
|
|
1049
|
457
|
50
|
66
|
|
|
871
|
$self->is_link and $self->_no_follow and $self->close and return; |
|
|
|
33
|
|
|
|
|
1050
|
|
|
|
|
|
|
|
1051
|
457
|
|
|
|
|
18866
|
my $dir_pat = $self->_dir_pattern; my $name; |
|
457
|
|
|
|
|
2720
|
|
1052
|
|
|
|
|
|
|
|
1053
|
457
|
100
|
|
|
|
758
|
if (wantarray) { |
1054
|
1
|
|
|
|
|
7
|
my @names = grep { $_ !~ $dir_pat } $self->io_handle->read; |
|
7
|
|
|
|
|
26
|
|
1055
|
|
|
|
|
|
|
|
1056
|
1
|
|
|
|
|
3
|
$self->close; return @names; |
|
1
|
|
|
|
|
5
|
|
1057
|
|
|
|
|
|
|
} |
1058
|
|
|
|
|
|
|
|
1059
|
456
|
|
100
|
|
|
939
|
while (not defined $name or $name =~ $dir_pat) { |
1060
|
704
|
100
|
|
|
|
3945
|
unless (defined ($name = $self->io_handle->read)) { |
1061
|
123
|
|
|
|
|
876
|
$self->close; return; |
|
123
|
|
|
|
|
506
|
|
1062
|
|
|
|
|
|
|
} |
1063
|
|
|
|
|
|
|
} |
1064
|
|
|
|
|
|
|
|
1065
|
333
|
|
|
|
|
3673
|
return $name; |
1066
|
|
|
|
|
|
|
} |
1067
|
|
|
|
|
|
|
|
1068
|
|
|
|
|
|
|
sub rel2abs { |
1069
|
4
|
|
|
4
|
1
|
20
|
my ($self, $base) = @_; |
1070
|
|
|
|
|
|
|
|
1071
|
4
|
100
|
|
|
|
47
|
return File::Spec->rel2abs( $self->name, defined $base ? "${base}" : undef ); |
1072
|
|
|
|
|
|
|
} |
1073
|
|
|
|
|
|
|
|
1074
|
|
|
|
|
|
|
sub relative { |
1075
|
47
|
|
|
47
|
1
|
606
|
$_[ 0 ]->_set_name( $_[ 0 ]->abs2rel ); return $_[ 0 ]; |
|
47
|
|
|
|
|
1841
|
|
1076
|
|
|
|
|
|
|
} |
1077
|
|
|
|
|
|
|
|
1078
|
|
|
|
|
|
|
sub reset { |
1079
|
1
|
|
|
1
|
1
|
2
|
my $self = shift; $self->close; |
|
1
|
|
|
|
|
3
|
|
1080
|
|
|
|
|
|
|
|
1081
|
1
|
|
|
|
|
13
|
$self->_assert( FALSE ); $self->_atomic( FALSE ); $self->_chomp ( FALSE ); |
|
1
|
|
|
|
|
32
|
|
|
1
|
|
|
|
|
29
|
|
1082
|
1
|
|
|
|
|
33
|
$self->_deep ( FALSE ); $self->_lock ( FALSE ); $self->_no_follow( FALSE ); |
|
1
|
|
|
|
|
29
|
|
|
1
|
|
|
|
|
33
|
|
1083
|
1
|
|
|
|
|
21
|
return $self; |
1084
|
|
|
|
|
|
|
} |
1085
|
|
|
|
|
|
|
|
1086
|
|
|
|
|
|
|
sub rmdir { |
1087
|
2
|
|
|
2
|
1
|
4
|
my $self = shift; |
1088
|
|
|
|
|
|
|
|
1089
|
2
|
100
|
|
|
|
44
|
CORE::rmdir $self->name |
1090
|
|
|
|
|
|
|
or $self->$_throw( 'Path [_1] not removed: [_2]', |
1091
|
|
|
|
|
|
|
[ $self->name, $OS_ERROR ] ); |
1092
|
1
|
|
|
|
|
67
|
return $self; |
1093
|
|
|
|
|
|
|
} |
1094
|
|
|
|
|
|
|
|
1095
|
|
|
|
|
|
|
sub rmtree { |
1096
|
2
|
|
|
2
|
1
|
4
|
my ($self, @args) = @_; ensure_class_loaded 'File::Path'; |
|
2
|
|
|
|
|
7
|
|
1097
|
|
|
|
|
|
|
|
1098
|
2
|
|
|
|
|
91
|
return File::Path::remove_tree( $self->name, @args ); |
1099
|
|
|
|
|
|
|
} |
1100
|
|
|
|
|
|
|
|
1101
|
|
|
|
|
|
|
sub seek { |
1102
|
5
|
|
|
5
|
1
|
56
|
my ($self, $posn, $whence) = @_; |
1103
|
|
|
|
|
|
|
|
1104
|
5
|
50
|
|
|
|
17
|
$self->is_open or $self->assert_open( is_mswin ? 'r' : 'r+' ); |
|
|
100
|
|
|
|
|
|
1105
|
5
|
|
|
|
|
44
|
CORE::seek $self->io_handle, $posn, $whence; $self->error_check; |
|
5
|
|
|
|
|
12
|
|
1106
|
5
|
|
|
|
|
7
|
return $self; |
1107
|
|
|
|
|
|
|
} |
1108
|
|
|
|
|
|
|
|
1109
|
|
|
|
|
|
|
sub separator { |
1110
|
1
|
50
|
|
1
|
1
|
18
|
defined $_[ 1 ] and $_[ 0 ]->_separator( $_[ 1 ] ); return $_[ 0 ]; |
|
1
|
|
|
|
|
22
|
|
1111
|
|
|
|
|
|
|
} |
1112
|
|
|
|
|
|
|
|
1113
|
|
|
|
|
|
|
sub set_binmode { |
1114
|
144
|
|
|
144
|
1
|
137
|
my $self = shift; |
1115
|
|
|
|
|
|
|
|
1116
|
144
|
50
|
|
|
|
343
|
is_ntfs and $self->$_push_layer(); # uncoverable branch true |
1117
|
|
|
|
|
|
|
|
1118
|
144
|
|
|
|
|
136
|
$self->$_sane_binmode( $_ ) for (@{ $self->_layers }); |
|
144
|
|
|
|
|
359
|
|
1119
|
|
|
|
|
|
|
|
1120
|
144
|
|
|
|
|
17703
|
return $self; |
1121
|
|
|
|
|
|
|
} |
1122
|
|
|
|
|
|
|
|
1123
|
|
|
|
|
|
|
sub set_lock { |
1124
|
144
|
100
|
|
144
|
1
|
162
|
my $self = shift; $self->_lock or return; |
|
144
|
|
|
|
|
1910
|
|
1125
|
|
|
|
|
|
|
|
1126
|
67
|
100
|
|
|
|
1002
|
my $async = $self->_lock == LOCK_NONBLOCKING ? TRUE : FALSE; |
1127
|
67
|
100
|
|
|
|
387
|
my $mode = $self->mode eq 'r' ? LOCK_SH : LOCK_EX; |
1128
|
|
|
|
|
|
|
|
1129
|
67
|
100
|
|
|
|
122
|
$async and $mode |= LOCK_NB; |
1130
|
67
|
50
|
|
|
|
1306
|
$self->_set_have_lock( (flock $self->io_handle, $mode) ? TRUE : FALSE ); |
1131
|
67
|
|
|
|
|
988
|
return $self; |
1132
|
|
|
|
|
|
|
} |
1133
|
|
|
|
|
|
|
|
1134
|
|
|
|
|
|
|
sub sibling { |
1135
|
1
|
|
|
1
|
1
|
2
|
my $self = shift; return $self->parent->child( @_ ); |
|
1
|
|
|
|
|
3
|
|
1136
|
|
|
|
|
|
|
} |
1137
|
|
|
|
|
|
|
|
1138
|
|
|
|
|
|
|
sub slurp { |
1139
|
13
|
|
|
13
|
1
|
39
|
my $self = shift; my $slurp = $self->all; |
|
13
|
|
|
|
|
29
|
|
1140
|
|
|
|
|
|
|
|
1141
|
12
|
100
|
|
|
|
67
|
wantarray or return $slurp; local $RS = $self->_separator; |
|
2
|
|
|
|
|
51
|
|
1142
|
|
|
|
|
|
|
|
1143
|
2
|
50
|
|
|
|
36
|
$self->_chomp or return split m{ (?<=\Q$RS\E) }mx, $slurp; |
1144
|
|
|
|
|
|
|
|
1145
|
2
|
|
|
|
|
3323
|
return map { CORE::chomp; $_ } split m{ (?<=\Q$RS\E) }mx, $slurp; |
|
1450
|
|
|
|
|
826
|
|
|
1450
|
|
|
|
|
1176
|
|
1146
|
|
|
|
|
|
|
} |
1147
|
|
|
|
|
|
|
|
1148
|
|
|
|
|
|
|
sub splitdir { |
1149
|
1
|
|
|
1
|
1
|
13
|
return File::Spec->splitdir( $_[ 0 ]->name ); |
1150
|
|
|
|
|
|
|
} |
1151
|
|
|
|
|
|
|
|
1152
|
|
|
|
|
|
|
sub splitpath { |
1153
|
1
|
|
|
1
|
1
|
13
|
return File::Spec->splitpath( $_[ 0 ]->name ); |
1154
|
|
|
|
|
|
|
} |
1155
|
|
|
|
|
|
|
|
1156
|
|
|
|
|
|
|
sub stat { |
1157
|
347
|
100
|
66
|
347
|
1
|
1098
|
my $self = shift; $self->exists or $self->is_open or return; |
|
347
|
|
|
|
|
502
|
|
1158
|
|
|
|
|
|
|
|
1159
|
345
|
|
|
|
|
10172
|
my %stat_hash = ( id => $self->filename ); |
1160
|
|
|
|
|
|
|
|
1161
|
345
|
50
|
|
|
|
526
|
@stat_hash{ STAT_FIELDS() } |
1162
|
|
|
|
|
|
|
= stat( $self->exists ? $self->name : $self->io_handle ); |
1163
|
|
|
|
|
|
|
|
1164
|
345
|
|
|
|
|
1198
|
return \%stat_hash; |
1165
|
|
|
|
|
|
|
} |
1166
|
|
|
|
|
|
|
|
1167
|
|
|
|
|
|
|
sub substitute { |
1168
|
4
|
|
100
|
4
|
1
|
10
|
my ($self, $search, $replace) = @_; $replace //= NUL; |
|
4
|
|
|
|
|
10
|
|
1169
|
|
|
|
|
|
|
|
1170
|
4
|
100
|
100
|
|
|
24
|
(defined $search and CORE::length $search) or return $self; |
1171
|
|
|
|
|
|
|
|
1172
|
2
|
|
|
|
|
4
|
my $perms = $self->$_untainted_perms; |
1173
|
2
|
|
|
|
|
29
|
my $wtr = $self->$_constructor( $self->name )->atomic; |
1174
|
|
|
|
|
|
|
|
1175
|
2
|
50
|
|
|
|
7
|
$perms and $wtr->perms( $perms ); |
1176
|
|
|
|
|
|
|
|
1177
|
2
|
|
|
|
|
6
|
for ($self->getlines) { s{ $search }{$replace}gmx; $wtr->print( $_ ) } |
|
6
|
|
|
|
|
35
|
|
|
6
|
|
|
|
|
11
|
|
1178
|
|
|
|
|
|
|
|
1179
|
2
|
|
|
|
|
7
|
$self->close; $wtr->close; |
|
2
|
|
|
|
|
5
|
|
1180
|
2
|
|
|
|
|
35
|
return $self; |
1181
|
|
|
|
|
|
|
} |
1182
|
|
|
|
|
|
|
|
1183
|
|
|
|
|
|
|
sub tail { |
1184
|
3
|
|
100
|
3
|
1
|
8
|
my ($self, $lines, @args) = @_; my @res; $lines //= 10; $self->close; |
|
3
|
|
|
|
|
4
|
|
|
3
|
|
|
|
|
11
|
|
|
3
|
|
|
|
|
6
|
|
1185
|
|
|
|
|
|
|
|
1186
|
3
|
|
|
|
|
8
|
while ($lines--) { |
1187
|
14
|
|
50
|
|
|
297
|
unshift @res, ($self->$_getline_backwards( @args ) or last); |
1188
|
|
|
|
|
|
|
} |
1189
|
|
|
|
|
|
|
|
1190
|
2
|
|
|
|
|
17
|
$self->close; |
1191
|
2
|
50
|
|
|
|
17
|
return wantarray ? @res : join NUL, @res; |
1192
|
|
|
|
|
|
|
} |
1193
|
|
|
|
|
|
|
|
1194
|
|
|
|
|
|
|
sub tell { |
1195
|
3
|
|
|
3
|
1
|
7
|
my $self = shift; |
1196
|
|
|
|
|
|
|
|
1197
|
3
|
0
|
|
|
|
9
|
$self->is_open or $self->assert_open( is_mswin ? 'r' : 'r+' ); |
|
|
50
|
|
|
|
|
|
1198
|
|
|
|
|
|
|
|
1199
|
3
|
|
|
|
|
14
|
return CORE::tell $self->io_handle; |
1200
|
|
|
|
|
|
|
} |
1201
|
|
|
|
|
|
|
|
1202
|
|
|
|
|
|
|
sub tempfile { |
1203
|
2
|
|
|
2
|
1
|
22
|
my ($self, $tmplt) = @_; my $tempdir; |
|
2
|
|
|
|
|
3
|
|
1204
|
|
|
|
|
|
|
|
1205
|
2
|
|
50
|
|
|
7
|
ensure_class_loaded 'File::Temp'; $tmplt ||= '%6.6dXXXX'; |
|
2
|
|
|
|
|
116
|
|
1206
|
|
|
|
|
|
|
|
1207
|
2
|
100
|
66
|
|
|
45
|
($tempdir = $self->name and -d $tempdir) or $tempdir = File::Spec->tmpdir; |
1208
|
|
|
|
|
|
|
|
1209
|
2
|
|
|
|
|
75
|
my $tmpfh = File::Temp->new |
1210
|
|
|
|
|
|
|
( DIR => $tempdir, TEMPLATE => (sprintf $tmplt, $PID) ); |
1211
|
2
|
|
|
|
|
904
|
my $t = $self->$_constructor( $tmpfh->filename )->file; |
1212
|
|
|
|
|
|
|
|
1213
|
2
|
|
|
|
|
26
|
$t->_set_io_handle( $tmpfh ); $t->_set_is_open( TRUE ); |
|
2
|
|
|
|
|
45
|
|
1214
|
2
|
|
|
|
|
42
|
$t->_set_mode( 'w+' ); |
1215
|
2
|
|
|
|
|
24
|
return $t; |
1216
|
|
|
|
|
|
|
} |
1217
|
|
|
|
|
|
|
|
1218
|
|
|
|
|
|
|
sub touch { |
1219
|
7
|
50
|
66
|
7
|
1
|
59
|
my ($self, $time) = @_; CORE::length $self->name or return; $time //= time; |
|
7
|
|
|
|
|
96
|
|
|
7
|
|
|
|
|
61
|
|
1220
|
|
|
|
|
|
|
|
1221
|
7
|
50
|
|
|
|
86
|
-e $self->name or $self->$_open_file( $self->$_open_args( 'w' ) )->close; |
1222
|
|
|
|
|
|
|
|
1223
|
7
|
|
|
|
|
94
|
utime $time, $time, $self->name; |
1224
|
7
|
|
|
|
|
124
|
return $self; |
1225
|
|
|
|
|
|
|
} |
1226
|
|
|
|
|
|
|
|
1227
|
|
|
|
|
|
|
sub unlink { |
1228
|
27
|
|
|
27
|
1
|
1820
|
return unlink $_[ 0 ]->name; |
1229
|
|
|
|
|
|
|
} |
1230
|
|
|
|
|
|
|
|
1231
|
|
|
|
|
|
|
sub unlock { |
1232
|
286
|
100
|
|
286
|
1
|
265
|
my $self = shift; $self->_lock or return; my $handle = $self->io_handle; |
|
286
|
|
|
|
|
3931
|
|
|
69
|
|
|
|
|
390
|
|
1233
|
|
|
|
|
|
|
|
1234
|
69
|
100
|
66
|
|
|
302
|
$handle and $handle->opened and flock $handle, LOCK_UN; |
1235
|
69
|
|
|
|
|
2646
|
$self->_set_have_lock( FALSE ); |
1236
|
69
|
|
|
|
|
1028
|
return $self; |
1237
|
|
|
|
|
|
|
} |
1238
|
|
|
|
|
|
|
|
1239
|
|
|
|
|
|
|
sub utf8 { |
1240
|
1
|
|
|
1
|
1
|
3
|
$_[ 0 ]->encoding( 'UTF-8' ); return $_[ 0 ]; |
|
1
|
|
|
|
|
4
|
|
1241
|
|
|
|
|
|
|
} |
1242
|
|
|
|
|
|
|
|
1243
|
|
|
|
|
|
|
sub visit { |
1244
|
1
|
|
|
1
|
1
|
11
|
my ($self, $cb, $args) = @_; |
1245
|
|
|
|
|
|
|
|
1246
|
1
|
|
|
|
|
4
|
my $iter = $self->iterator( $args ); my $state = {}; |
|
1
|
|
|
|
|
2
|
|
1247
|
|
|
|
|
|
|
|
1248
|
1
|
|
|
|
|
3
|
while (defined (my $entry = $iter->())) { |
1249
|
9
|
|
|
|
|
10
|
local $_ = $entry; my $r = $cb->( $entry, $state ); |
|
9
|
|
|
|
|
16
|
|
1250
|
|
|
|
|
|
|
|
1251
|
9
|
100
|
100
|
|
|
51
|
ref $r and not ${ $r } and last; |
|
8
|
|
|
|
|
78
|
|
1252
|
|
|
|
|
|
|
} |
1253
|
|
|
|
|
|
|
|
1254
|
1
|
|
|
|
|
21
|
return $state; |
1255
|
|
|
|
|
|
|
} |
1256
|
|
|
|
|
|
|
|
1257
|
|
|
|
|
|
|
sub write { |
1258
|
15
|
|
|
15
|
1
|
42
|
my ($self, @args) = @_; $self->assert_open( 'w' ); |
|
15
|
|
|
|
|
21
|
|
1259
|
|
|
|
|
|
|
|
1260
|
|
|
|
|
|
|
my $length = @args |
1261
|
|
|
|
|
|
|
? $self->io_handle->write( @args ) |
1262
|
15
|
50
|
|
|
|
32
|
: $self->io_handle->write( ${ $self->buffer }, $self->length ); |
|
15
|
|
|
|
|
17
|
|
1263
|
|
|
|
|
|
|
|
1264
|
15
|
50
|
|
|
|
347
|
$self->error_check; scalar @args or $self->clear; |
|
15
|
|
|
|
|
33
|
|
1265
|
15
|
|
|
|
|
22
|
return $length; |
1266
|
|
|
|
|
|
|
} |
1267
|
|
|
|
|
|
|
|
1268
|
|
|
|
|
|
|
# Method installer |
1269
|
|
|
|
|
|
|
my $_proxy = sub { # Methods handled by the IO::Handle object |
1270
|
|
|
|
|
|
|
my ($proxy, $chain, $mode) = @_; |
1271
|
|
|
|
|
|
|
|
1272
|
|
|
|
|
|
|
my $package = caller; $package->can( $proxy ) and return; |
1273
|
|
|
|
|
|
|
|
1274
|
|
|
|
|
|
|
install_sub { into => $package, as => $proxy, code => sub { |
1275
|
9
|
100
|
|
9
|
|
2097
|
my $self = shift; defined $mode and $self->assert_open( $mode ); |
|
9
|
|
|
|
|
28
|
|
1276
|
|
|
|
|
|
|
|
1277
|
9
|
100
|
|
|
|
29
|
defined $self->io_handle or throw InvocantUndefined, [ $proxy ]; |
1278
|
|
|
|
|
|
|
|
1279
|
8
|
|
|
|
|
66
|
my @results = $self->io_handle->$proxy( @_ ); # Mustn't copy stack args |
1280
|
|
|
|
|
|
|
|
1281
|
8
|
100
|
|
|
|
137
|
$self->error_check; $chain and return $self; |
|
8
|
|
|
|
|
20
|
|
1282
|
|
|
|
|
|
|
|
1283
|
7
|
50
|
|
|
|
32
|
return wantarray ? @results : $results[ 0 ]; |
1284
|
|
|
|
|
|
|
} }; |
1285
|
|
|
|
|
|
|
}; |
1286
|
|
|
|
|
|
|
|
1287
|
|
|
|
|
|
|
$_proxy->( 'autoflush', TRUE ); |
1288
|
|
|
|
|
|
|
$_proxy->( 'eof' ); |
1289
|
|
|
|
|
|
|
$_proxy->( 'fileno' ); |
1290
|
|
|
|
|
|
|
$_proxy->( 'flush', TRUE ); |
1291
|
|
|
|
|
|
|
$_proxy->( 'getc', FALSE, 'r' ); |
1292
|
|
|
|
|
|
|
$_proxy->( 'sysread', FALSE, O_RDONLY ); |
1293
|
|
|
|
|
|
|
$_proxy->( 'syswrite', FALSE, O_CREAT | O_WRONLY ); |
1294
|
|
|
|
|
|
|
$_proxy->( 'truncate', TRUE ); |
1295
|
|
|
|
|
|
|
|
1296
|
|
|
|
|
|
|
1; |
1297
|
|
|
|
|
|
|
|
1298
|
|
|
|
|
|
|
__END__ |