Net-SFTP-Server

 view release on metacpan or  search on metacpan

lib/Net/SFTP/Server/FS.pm  view on Meta::CPAN

$errno2status[Errno::ENOENT] = SSH_FX_NO_SUCH_FILE;
$errno2status[Errno::EBADF] = SSH_FX_NO_SUCH_FILE;
$errno2status[Errno::ELOOP] = SSH_FX_NO_SUCH_FILE;
$errno2status[Errno::EPERM] = SSH_FX_PERMISSION_DENIED;
$errno2status[Errno::EACCES] = SSH_FX_PERMISSION_DENIED;
$errno2status[Errno::EFAULT] = SSH_FX_PERMISSION_DENIED;
$errno2status[Errno::ENAMETOOLONG] = SSH_FX_BAD_MESSAGE;
$errno2status[Errno::EINVAL] = SSH_FX_BAD_MESSAGE;
$errno2status[Errno::ENOSYS] = SSH_FX_OP_UNSUPPORTED;

sub errno_to_status {
    my ($self, $errno) = @_;
    $errno2status[$errno] // SSH_FX_FAILURE;
}

sub push_status_errno_response {
    my ($self, $id) = @_;
    $self->push_status_response($id, $self->errno_to_status($!), $!);
}

sub sftp_open_flags_to_sysopen {
    my ($self, $flags) = @_;
    my $posix = 0;
    if ($flags & SSH_FXF_READ) {
	if ($flags & SSH_FXF_WRITE) {
	    $posix = O_RDWR;
	}
	else {
	    $posix = O_RDONLY;
	}
    }
    elsif ($flags & SSH_FXF_WRITE) {
	$posix = O_WRONLY;
    }
    if ($flags & SSH_FXF_CREAT) {
	$posix |= O_CREAT;
    }
    if ($flags & SSH_FXF_TRUNC) {
	$posix |= O_TRUNC;
    }
    if ($flags & SSH_FXF_EXCL) {
	$posix |= O_EXCL;
    }
    $debug and $debug & 128 and _debug "flags $flags to posix $posix";
    $posix;
}

sub _set_attrs {
    my ($obj, $attrs) = @_;
    local $@;
    local $SIG{__DIE__};
    eval {
	if ($attrs) {
	    if (defined $attrs->{size}) {
		truncate $obj, $attrs->{size} or return;
	    }
	    if (defined $attrs->{permissions}) {
		chmod $attrs->{permissions}, $obj or return;
	    }
	    if (defined $attrs->{gid}) {
		chown $attrs->{uid}, $attrs->{gid}, $obj or return;
	    }
	    if (defined $attrs->{atime}) {
		utime $attrs->{atime}, $attrs->{mtime}, $obj or return;
	    }
	}
	1;
    };
}

sub handle_command_open_v3 {
    my ($self, $id, $path, $flags, $attrs) = @_;
    my $writable = $flags & SSH_FXF_WRITE;
    my $pflags = $self->sftp_open_flags_to_sysopen($flags);
    my $perms = $attrs->{mode};
    my $old_umask;
    if (defined $perms) {
	$old_umask = umask $perms;
    }
    else {
	$perms = 0666;
    }
    my $fh;
    unless (sysopen $fh, $path, $pflags, $perms) {
	$self->push_status_errno_response($id);
	umask $old_umask if defined $old_umask;
	return;
    }
    umask $old_umask if defined $old_umask;
    if ($writable) {
	_set_attrs($path, $attrs)
	    or $self->send_status_errno_response($id);
    }
    my $hid = $self->save_file_handler($fh, $flags, $perms);
    $debug and $debug & 2 and _debug "file $path open as $hid (pkt id: $id)";
    $self->push_handle_response($id, $hid);
}

sub handle_command_read_v3 {
    my ($self, $id, $hid, $off, $len) = @_;
    my $fh = $self->get_file_handler($hid) //
	return $self->push_status_response($id, SSH_FX_FAILURE,
					   "Bad handler");
    $len = 65536 if $len > 65536;

    sysseek($fh, $off, 0) // return $self->push_status_errno_response($id);
    my $bytes = sysread($fh, my($data), $len) //
	return $self->push_status_errno_response($id);
    $bytes == 0 and
	return $self->push_status_response($id, SSH_FX_EOF);
    # TODO: build packet on buffer_out to reduce data copying
    $self->push_packet(uint8 => SSH_FXP_DATA,
		       uint32 => $id,
		       str => $data);
}

sub handle_command_write_v3 {
    my ($self, $id, $hid, $off) = @_;
    my $fh = $self->get_file_handler($hid) //
	return $self->push_status_response($id, SSH_FX_FAILURE,
					   "Bad handler");



( run in 1.961 second using v1.01-cache-2.11-cpan-71847e10f99 )