shell bypass 403
use strict; use warnings;
package IO::All::File;
use IO::All::Filesys -base;
use IO::All -base;
use IO::File;
use File::Copy ();
#===============================================================================
const type => 'file';
field tied_file => undef;
#===============================================================================
sub file {
my $self = shift;
bless $self, __PACKAGE__;
# should we die here if $self->name is already set and there are args?
if (@_ && @_ > 1) {
$self->name( $self->_spec_class->catfile( @_ ) )
} elsif (@_) {
$self->name($_[0])
}
return $self->_init;
}
sub file_handle {
my $self = shift;
bless $self, __PACKAGE__;
$self->_handle(shift) if @_;
return $self->_init;
}
#===============================================================================
sub assert_filepath {
my $self = shift;
my $name = $self->pathname
or return;
my $directory;
(undef, $directory) = File::Spec->splitpath($self->pathname);
$self->_assert_dirpath($directory);
}
sub assert_open_backwards {
my $self = shift;
return if $self->is_open;
require File::ReadBackwards;
my $file_name = $self->pathname;
my $io_handle = File::ReadBackwards->new($file_name)
or $self->throw("Can't open $file_name for backwards:\n$!");
$self->io_handle($io_handle);
$self->is_open(1);
}
sub _assert_open {
my $self = shift;
return if $self->is_open;
$self->mode(shift) unless $self->mode;
$self->open;
}
sub assert_tied_file {
my $self = shift;
return $self->tied_file || do {
eval {require Tie::File};
$self->throw("Tie::File required for file array operations:\n$@")
if $@;
my $array_ref = do { my @array; \@array };
my $name = $self->pathname;
my @options = $self->_rdonly ? (mode => O_RDONLY) : ();
push @options, (recsep => $self->separator);
tie @$array_ref, 'Tie::File', $name, @options;
$self->throw("Can't tie 'Tie::File' to '$name':\n$!")
unless tied @$array_ref;
$self->tied_file($array_ref);
};
}
sub open {
my $self = shift;
$self->is_open(1);
$self->assert_filepath if $self->_assert;
my ($mode, $perms) = @_;
$self->mode($mode) if defined $mode;
$self->mode('<') unless defined $self->mode;
$self->perms($perms) if defined $perms;
my @args = ($self->mode);
push @args, $self->perms if defined $self->perms;
if (defined $self->pathname) {
$self->io_handle(IO::File->new);
$self->io_handle->open($self->pathname, @args)
or $self->throw($self->open_msg);
}
elsif (defined $self->_handle and
not $self->io_handle->opened
) {
# XXX Not tested
$self->io_handle->fdopen($self->_handle, @args);
}
$self->set_lock;
$self->_set_binmode;
}
sub exists { -f shift->pathname }
my %mode_msg = (
'>' => 'output',
'<' => 'input',
'>>' => 'append',
);
sub open_msg {
my $self = shift;
my $name = defined $self->pathname
? " '" . $self->pathname . "'"
: '';
my $direction = defined $mode_msg{$self->mode}
? ' for ' . $mode_msg{$self->mode}
: '';
return qq{Can't open file$name$direction:\n$!};
}
#===============================================================================
sub copy {
my ($self, $new) = @_;
File::Copy::copy($self->name, $new)
or die "failed to copy $self to $new: $!";
$self->file($new)
}
sub close {
my $self = shift;
return unless $self->is_open;
$self->is_open(0);
my $io_handle = $self->io_handle;
$self->unlock;
$self->io_handle(undef);
$self->mode(undef);
if (my $tied_file = $self->tied_file) {
if (ref($tied_file) eq 'ARRAY') {
untie @$tied_file;
}
else {
untie %$tied_file;
}
$self->tied_file(undef);
return 1;
}
$io_handle->close(@_)
if defined $io_handle;
return $self;
}
sub empty {
my $self = shift;
-z $self->pathname;
}
sub filepath {
my $self = shift;
my ($volume, $path) = $self->splitpath;
return File::Spec->catpath($volume, $path, '');
}
sub getline_backwards {
my $self = shift;
$self->assert_open_backwards;
return $self->io_handle->readline;
}
sub getlines_backwards {
my $self = shift;
my @lines;
while (defined (my $line = $self->getline_backwards)) {
push @lines, $line;
}
return @lines;
}
sub head {
my $self = shift;
my $lines = shift || 10;
my @return;
$self->close;
LINES:
while ($lines--) {
if (defined (my $l = $self->getline)) {
push @return, $l;
}
else {
last LINES;
}
}
$self->close;
return wantarray ? @return : join '', @return;
}
sub tail {
my $self = shift;
my $lines = shift || 10;
my @return;
$self->close;
while ($lines--) {
unshift @return, ($self->getline_backwards or last);
}
$self->close;
return wantarray ? @return : join '', @return;
}
sub touch {
my $self = shift;
return $self->SUPER::touch(@_)
if -e $self->pathname;
return $self if $self->is_open;
my $mode = $self->mode;
$self->mode('>>')->open->close;
$self->mode($mode);
return $self;
}
sub unlink {
my $self = shift;
unlink $self->pathname;
}
#===============================================================================
sub _overload_table {
my $self = shift;
(
$self->SUPER::_overload_table(@_),
'file > file' => '_overload_file_to_file',
'file < file' => '_overload_file_from_file',
'${} file' => '_overload_file_as_scalar',
'@{} file' => '_overload_file_as_array',
'%{} file' => '_overload_file_as_dbm',
)
}
sub _overload_file_to_file {
require File::Copy;
File::Copy::copy($_[1]->pathname, $_[2]->pathname);
$_[2];
}
sub _overload_file_from_file {
require File::Copy;
File::Copy::copy($_[2]->pathname, $_[1]->pathname);
$_[1];
}
sub _overload_file_as_array {
$_[1]->assert_tied_file;
}
sub _overload_file_as_dbm {
$_[1]->dbm
unless $_[1]->isa('IO::All::DBM');
$_[1]->_assert_open;
}
sub _overload_file_as_scalar {
my $scalar = $_[1]->scalar;
return \$scalar;
}
1;