Net-SSH2
view release on metacpan or search on metacpan
#else
void
net_ss_block_directions(SSH2* ss)
CODE:
croak("libssh2 version 1.0 or higher required for block_directions support");
#endif
#if LIBSSH2_VERSION_NUM >= 0x010209
SV *
net_ss_timeout(SSH2* ss, SV *timeout = &PL_sv_undef)
PREINIT:
long r;
CODE:
if (items > 1)
libssh2_session_set_timeout(ss->session,
(SvOK(timeout) ? SvUV(timeout) : 0));
r = libssh2_session_get_timeout(ss->session);
RETVAL = (r > 0 ? newSVuv(r) : &PL_sv_undef);
OUTPUT:
RETVAL
#else
void
net_ss_timeout(SSH2* ss, long timeout)
CODE:
croak("libssh2 version 1.2.9 or higher required for set_timeout support");
#endif
SSH2_BOOL
net_ss_blocking(SSH2* ss, SSH2_BOOL blocking = 0)
CODE:
if (items > 1)
libssh2_session_set_blocking(ss->session, blocking);
RETVAL = libssh2_session_get_blocking(ss->session);
OUTPUT:
RETVAL
void
net_ss_DESTROY(SSH2* ss)
CODE:
debug("%s::DESTROY object 0x%x\n", class, ss);
libssh2_session_free(ss->session);
if (ss->socket)
SvREFCNT_dec(ss->socket);
if (ss->hostname)
SvREFCNT_dec(ss->hostname);
Safefree(ss);
void
net_ss_debug(SV*, IV debug)
CODE:
net_ss_debug_out = debug & 1; /* allow for future flags */
void
net_ss_version(...)
PPCODE:
EXTEND(SP, 3);
ST(0) = sv_2mortal(newSVpv(LIBSSH2_VERSION, 0));
if (GIMME_V != G_ARRAY)
XSRETURN(1);
#ifdef LIBSSH2_VERSION_NUM
ST(1) = sv_2mortal(newSVuv(LIBSSH2_VERSION_NUM));
#else
ST(1) = &PL_sv_undef;
#endif
ST(2) = sv_2mortal(newSVpv(LIBSSH2_SSH_DEFAULT_BANNER, 0));
XSRETURN(3);
SSH2_NERROR
net_ss_banner(SSH2* ss, SSH2_CHARP banner)
PREINIT:
SV* full_banner;
CODE:
full_banner = sv_2mortal(newSVpvf("SSH-2.0-%s", banner));
RETVAL = libssh2_banner_set(ss->session, SvPVbyte_nolen(full_banner));
save_eagain(ss->session, RETVAL);
OUTPUT:
RETVAL
SSH2_ERROR
net_ss_error(SSH2* ss)
PREINIT:
char* errstr;
int errlen;
CODE:
RETVAL = libssh2_session_last_error(ss->session, &errstr, &errlen, 0);
if(GIMME_V == G_ARRAY) {
SV *errcode_sv;
if (RETVAL == LIBSSH2_ERROR_NONE)
XSRETURN_EMPTY;
EXTEND(SP, 3);
ST(0) = sv_2mortal(newSViv(RETVAL));
if ((-RETVAL > 0) && (-RETVAL < countof(xs_libssh2_error)))
errcode_sv = newSVpvf("LIBSSH2_ERROR_%s", xs_libssh2_error[-RETVAL]);
else
errcode_sv = newSVpvf("LIBSSH2_ERROR_UNKNOWN(%d)", RETVAL);
ST(1) = sv_2mortal(errcode_sv);
ST(2) = (errstr ? sv_2mortal(newSVpvn(errstr, errlen)) : &PL_sv_undef);
XSRETURN(3);
}
OUTPUT:
RETVAL
void
net_ss__set_error(SSH2 *ss, int errcode = 0, SSH2_CHARP_OR_NULL errmsg = NULL)
CODE:
libssh2_session_set_last_error(ss->session, errcode, errmsg);
SSH2_NERROR
net_ss__method(SSH2* ss, SSH2_METHOD type, SSH2_CHARP_OR_NULL prefs = NULL)
CODE:
/* if there are no other parameters, return the current value */
if (items == 2) {
const char *method = libssh2_session_methods(ss->session, (int)type);
if (!method)
XSRETURN_EMPTY;
ss->sv_ss = SvRV(ST(0)); /* don't keep a reference, just store it */
SvREFCNT_dec(ss->rgsv_cb[type]);
libssh2_session_callback_set(ss->session,
type, callback ? cb_as_void_ptr(msg_cb[type]) : NULL);
SvREFCNT_inc(callback);
ss->rgsv_cb[type] = callback;
RETVAL = 1;
OUTPUT:
RETVAL
SSH2_NERROR
net_ss__startup(SSH2* ss, int fd, SV *socket, SV* hostname, int port)
CODE:
RETVAL = libssh2_session_startup(ss->session, fd);
if ((RETVAL >= 0) && SvOK(socket)) {
if (ss->socket)
sv_2mortal(ss->socket);
ss->socket = newSVsv(socket);
ss->hostname = newSVsv(hostname);
ss->port = port;
}
save_eagain(ss->session, RETVAL);
OUTPUT:
RETVAL
SV *
net_ss_hostname(SSH2* ss)
CODE:
RETVAL = (ss->hostname ? newSVsv(ss->hostname) : &PL_sv_undef);
OUTPUT:
RETVAL
int
net_ss_port(SSH2* ss)
CODE:
RETVAL = ss->port;
OUTPUT:
RETVAL
SV *
net_ss_sock(SSH2* ss)
CODE:
RETVAL = (ss->socket ? newSVsv(ss->socket) : &PL_sv_undef);
OUTPUT:
RETVAL
SSH2_NERROR
net_ss_disconnect(SSH2* ss, SSH2_CHARP description = "", \
int reason = SSH_DISCONNECT_BY_APPLICATION, SSH2_CHARP lang = "")
CODE:
RETVAL = libssh2_session_disconnect_ex(ss->session, reason, description, lang);
save_eagain(ss->session, RETVAL);
OUTPUT:
RETVAL
void
net_ss_hostkey_hash(SSH2* ss, SSH2_HOSTKEY_HASH type)
PREINIT:
const char* hash;
static STRLEN rglen[] = { 16/*MD5*/, 20/*SHA1*/ };
PPCODE:
if (type < 1 || type > countof(rglen)) {
croak("%s::hostkey: unknown hostkey hash: %d",
class, (int)type);
}
if ((hash = (const char*)libssh2_hostkey_hash(ss->session, type))) {
PUSHs(sv_2mortal(newSVpvn(hash, rglen[type-1])));
XSRETURN(1);
}
XSRETURN_EMPTY;
void
net_ss_remote_hostkey(SSH2* ss)
PREINIT:
const char *key_pv;
size_t key_len;
int type_int;
PPCODE:
if ((key_pv = libssh2_session_hostkey(ss->session, &key_len, &type_int))) {
XPUSHs(sv_2mortal(newSVpvn(key_pv, key_len)));
if (GIMME_V != G_ARRAY)
XSRETURN(1);
else {
XPUSHs(sv_2mortal(newSViv(type_int)));
XSRETURN(2);
}
}
else
XSRETURN_EMPTY;
SSH2_CHARP_OR_NULL
net_ss__auth_list(SSH2* ss, SV *username = &PL_sv_undef)
PREINIT:
const char* pv_username = NULL;
STRLEN len_username = 0;
CODE:
if (SvOK(username))
pv_username = SvPVbyte(username, len_username);
RETVAL = libssh2_userauth_list(ss->session, pv_username, len_username);
OUTPUT:
RETVAL
SSH2_RC
net_ss_auth_ok(SSH2* ss)
CODE:
RETVAL = libssh2_userauth_authenticated(ss->session);
OUTPUT:
RETVAL
SSH2_NERROR
net_ss_auth_password(SSH2* ss, \
SV* username, SV* password = &PL_sv_undef, \
SV* callback = &PL_sv_undef)
PREINIT:
STRLEN len_username, len_password;
const char *pv_username, *pv_password;
int i, ok;
CODE:
pv_username = SvPVbyte(username, len_username);
/* if we don't have a password, try for an unauthenticated login */
if (!SvPOK(password)) {
/* That's how libssh2 tells you authentication 'none' is valid */
RETVAL = (((libssh2_userauth_list(ss->session, pv_username, len_username) == NULL) &&
libssh2_userauth_authenticated(ss->session)) ? 0 : -1);
}
else {
if (SvOK(callback)) {
if (!(SvROK(callback) && SvTYPE(SvRV(callback)) == SVt_PVCV))
Perl_croak(aTHX_ "%s::auth_password: callback must be CODE ref", class);
else {
AV *cb_args = (AV*)sv_2mortal((SV*)newAV());
av_push(cb_args, newSVsv(callback));
av_push(cb_args, newSVsv(ST(0))); /*session */
av_push(cb_args, newSVsv(username));
set_cb_args(aTHX_ cb_args);
}
}
RETVAL
SSH2_PUBLICKEY*
net_ss_public_key(SSH2* ss)
CODE:
NEW_PUBLICKEY(libssh2_publickey_init(ss->session));
OUTPUT:
RETVAL
#undef class
MODULE = Net::SSH2 PACKAGE = Net::SSH2::Channel PREFIX = net_ch_
PROTOTYPES: DISABLE
#define class "Net::SSH2::Channel"
void
net_ch_DESTROY(SSH2_CHANNEL* ch)
CODE:
debug("%s::DESTROY\n", class);
libssh2_channel_free(ch->channel);
SvREFCNT_dec(ch->sv_ss);
Safefree(ch);
SV *
net_ch_session(SSH2_CHANNEL* ch)
CODE:
RETVAL = newRV_inc(ch->sv_ss);
OUTPUT:
RETVAL
SSH2_NERROR
net_ch__setenv(SSH2_CHANNEL* ch, SV *key, SV *value)
PREINIT:
int i, success = 0;
const char* pv_key, * pv_value;
STRLEN len_key, len_value;
CODE:
pv_key = SvPVbyte(key, len_key);
pv_value = SvPVbyte(value, len_value);
RETVAL = libssh2_channel_setenv_ex(ch->channel,
(char*)pv_key, len_key,
(char*)pv_value, len_value);
save_eagain(ch->ss->session, RETVAL);
OUTPUT:
RETVAL
#if LIBSSH2_VERSION_NUM >= 0x010208
void
net_ch__exit_signal(SSH2_CHANNEL* ch)
PREINIT:
char *exitsignal;
char *errmsg;
char *langtag;
size_t exitsignal_len;
size_t errmsg_len;
size_t langtag_len;
int retcount = 1;
PPCODE:
if (!libssh2_channel_get_exit_signal(ch->channel,
&exitsignal, &exitsignal_len,
&errmsg, &errmsg_len,
&langtag, &langtag_len)) {
LIBSSH2_SESSION *session = ch->ss->session;
libssh2_session_set_last_error(session, 0, NULL);
if (exitsignal) {
XPUSHs(sv_2mortal(newSVpvn(exitsignal, exitsignal_len)));
if (GIMME_V == G_ARRAY) {
XPUSHs(errmsg ? sv_2mortal(newSVpvn(errmsg, errmsg_len)) : &PL_sv_undef);
XPUSHs(langtag ? sv_2mortal(newSVpvn(langtag, langtag_len)) : &PL_sv_undef);
retcount = 3;
}
libssh2_free(session, exitsignal);
if (errmsg) libssh2_free(session, errmsg);
if (langtag) libssh2_free(session, langtag);
}
else
XPUSHs(&PL_sv_no);
XSRETURN(retcount);
}
else
XSRETURN(0);
#else
void
net_ch__exit_signal(SSH2_CHANNEL* ch)
CODE:
croak("libssh2 version 1.2.8 or higher required for exit_signal support");
#endif
SSH2_BYTES
net_ch_eof(SSH2_CHANNEL* ch)
CODE:
RETVAL = libssh2_channel_eof(ch->channel);
save_eagain(ch->ss->session, RETVAL);
OUTPUT:
RETVAL
SSH2_NERROR
net_ch_send_eof(SSH2_CHANNEL* ch)
CODE:
RETVAL = libssh2_channel_send_eof(ch->channel);
save_eagain(ch->ss->session, RETVAL);
OUTPUT:
RETVAL
SSH2_NERROR
net_ch_close(SSH2_CHANNEL* ch)
CODE:
RETVAL = libssh2_channel_close(ch->channel);
save_eagain(ch->ss->session, RETVAL);
OUTPUT:
RETVAL
SSH2_NERROR
net_ch__wait_closed(SSH2_CHANNEL* ch)
CODE:
/*
1. in blocking mode, write all the data.
2. in non-blocking mode, write as much data as possible without
blocking.
3. if some error happens...
a. if some data was already written, discard the error and
report the number of bytes written.
b. if no data was written, report the error.
*/
pv_buffer = SvPVbyte(buffer, len_buffer);
while (offset < len_buffer) {
count = libssh2_channel_write_ex(ch->channel, ext,
pv_buffer + offset,
len_buffer - offset);
if (count >= 0)
offset += count;
else if ((count != LIBSSH2_ERROR_EAGAIN) ||
!libssh2_session_get_blocking(ch->ss->session))
break;
}
if (offset || (count == 0)) /* yes, zero is a valid value */
RETVAL = offset;
else {
save_eagain(ch->ss->session, count);
RETVAL = -1;
}
OUTPUT:
RETVAL
#if LIBSSH2_VERSION_NUM >= 0x010100
SSH2_BYTES
net_ch_receive_window_adjust(SSH2_CHANNEL *ch, unsigned long adjustment, SV *force = &PL_sv_undef)
PREINIT:
unsigned int bytes;
CODE:
RETVAL = libssh2_channel_receive_window_adjust2(ch->channel, adjustment,
SvTRUE(force), &bytes);
if (RETVAL)
save_eagain(ch->ss->session, RETVAL);
else
RETVAL = bytes;
OUTPUT:
RETVAL
#else
void
net_ch_receive_window_adjust(SSH2_CHANNEL* ch, ...)
CODE:
croak("libssh2 version 1.1 or higher required for receive_window_adjust support");
#endif
#if LIBSSH2_VERSION_NUM >= 0x010200
void
net_ch_window_write(SSH2_CHANNEL* ch)
PREINIT:
unsigned long window_size_initial = 0;
PPCODE:
XPUSHs(sv_2mortal(newSVuv(libssh2_channel_window_write_ex(ch->channel,
&window_size_initial))));
if (GIMME_V == G_ARRAY) {
XPUSHs(sv_2mortal(newSVuv(window_size_initial)));
XSRETURN(2);
}
else
XSRETURN(1);
void
net_ch_window_read(SSH2_CHANNEL *ch)
PREINIT:
unsigned long read_avail = 0;
unsigned long window_size_initial = 0;
PPCODE:
XPUSHs(sv_2mortal(newSVuv(libssh2_channel_window_read_ex(ch->channel,
&read_avail,
&window_size_initial))));
if (GIMME_V == G_ARRAY) {
XPUSHs(sv_2mortal(newSVuv(read_avail)));
XPUSHs(sv_2mortal(newSVuv(window_size_initial)));
XSRETURN(3);
}
else
XSRETURN(1);
#else
void
net_ch_window_write(SSH2_CHANNEL* ch)
CODE:
croak("libssh2 version 1.2 or higher required for window_write support");
void
net_ch_window_read(SSH2_CHANNEL* ch)
CODE:
croak("libssh2 version 1.2 or higher required for window_read support");
#endif
SSH2_BYTES
net_ch_flush(SSH2_CHANNEL* ch, SSH2_STREAM_ID ext = 0)
CODE:
RETVAL = libssh2_channel_flush_ex(ch->channel, ext);
save_eagain(ch->ss->session, RETVAL);
OUTPUT:
RETVAL
#undef class
MODULE = Net::SSH2 PACKAGE = Net::SSH2::Listener PREFIX = net_ls_
PROTOTYPES: DISABLE
#define class "Net::SSH2::Listener"
void
net_ls_DESTROY(SSH2_LISTENER* ls)
CODE:
debug("%s::DESTROY\n", class);
libssh2_channel_forward_cancel(ls->listener);
SvREFCNT_dec(ls->sv_ss);
Safefree(ls);
SSH2_CHANNEL*
net_ls_accept(SSH2_LISTENER* ls)
PREINIT:
SSH2* ss;
CODE:
ss = ls->ss;
NEW_CHANNEL(libssh2_channel_forward_accept(ls->listener));
OUTPUT:
RETVAL
#undef class
MODULE = Net::SSH2 PACKAGE = Net::SSH2::SFTP PREFIX = net_sf_
PROTOTYPES: DISABLE
#define class "Net::SSH2::SFTP"
void
net_sf_DESTROY(SSH2_SFTP* sf)
CODE:
debug("%s::DESTROY\n", class);
libssh2_sftp_shutdown(sf->sftp);
debug("%s::DESTROY freeing session\n", class);
SvREFCNT_dec(sf->sv_ss);
Safefree(sf);
SV *
net_sf_session(SSH2_SFTP* sf)
CODE:
RETVAL = newRV_inc(sf->sv_ss);
OUTPUT:
RETVAL
void
net_sf_error(SSH2_SFTP* sf)
PREINIT:
unsigned long error;
SV *errstr;
PPCODE:
error = libssh2_sftp_last_error(sf->sftp);
ST(0) = sv_2mortal(newSVuv(error));
if (GIMME_V == G_ARRAY) {
EXTEND(SP, 2);
if ((error >= 0) && (error < countof(sftp_error)))
errstr = newSVpvf("SSH_FX_%s", sftp_error[error]);
else
errstr = newSVpvf("SSH_FX_UNKNOWN(%lu)", error);
ST(1) = sv_2mortal(errstr);
XSRETURN(2);
}
else
XSRETURN(1);
#define XLATFLAG(posix, fxf) do { \
if (flags & posix || \
l_flags == 0 && posix == 0 && flags == posix /* 0-valued flag */) { \
l_flags |= fxf; \
flags &= ~posix; \
} \
} while(0)
SSH2_FILE*
net_sf_open(SSH2_SFTP* sf, SV* file, int flags = O_RDONLY, int mode = 0666)
PREINIT:
long l_flags = 0;
const char* pv_file;
STRLEN len_file;
CODE:
pv_file = SvPVbyte(file, len_file);
/* map POSIX O_* to LIBSSH2_FXF_* (can't assume they're the same) */
XLATFLAG(O_RDWR, LIBSSH2_FXF_READ | LIBSSH2_FXF_WRITE);
XLATFLAG(O_RDONLY, LIBSSH2_FXF_READ);
XLATFLAG(O_WRONLY, LIBSSH2_FXF_WRITE);
XLATFLAG(O_APPEND, LIBSSH2_FXF_APPEND);
XLATFLAG(O_CREAT, LIBSSH2_FXF_CREAT);
XLATFLAG(O_TRUNC, LIBSSH2_FXF_TRUNC);
XLATFLAG(O_EXCL, LIBSSH2_FXF_EXCL);
if (flags)
croak("%s::open: unknown flag value: %d", class, flags);
NEW_FILE(libssh2_sftp_open_ex(sf->sftp, (char*)pv_file, len_file,
l_flags, mode, LIBSSH2_SFTP_OPENFILE));
OUTPUT:
RETVAL
#undef XLATFLAG
SSH2_DIR*
net_sf_opendir(SSH2_SFTP* sf, SV* dir)
PREINIT:
const char* pv_dir;
STRLEN len_dir;
CODE:
pv_dir = SvPVbyte(dir, len_dir);
NEW_DIR(libssh2_sftp_open_ex(sf->sftp, (char*)pv_dir, len_dir,
0/*flags*/, 0/*mode*/, LIBSSH2_SFTP_OPENDIR));
OUTPUT:
RETVAL
SSH2_NERROR
net_sf_unlink(SSH2_SFTP* sf, SV* file)
PREINIT:
char* pv_file;
STRLEN len_file;
CODE:
pv_file = SvPVbyte(file, len_file);
RETVAL = libssh2_sftp_unlink_ex(sf->sftp, (char*)pv_file, len_file);
OUTPUT:
RETVAL
SSH2_NERROR
net_sf_rename(SSH2_SFTP* sf, SV* old, SV* new, \
long flags = ( LIBSSH2_SFTP_RENAME_OVERWRITE | \
LIBSSH2_SFTP_RENAME_ATOMIC | \
LIBSSH2_SFTP_RENAME_NATIVE ) )
PREINIT:
const char* pv_old, * pv_new;
STRLEN len_old, len_new;
CODE:
pv_old = SvPVbyte(old, len_old);
pv_new = SvPVbyte(new, len_new);
RETVAL = libssh2_sftp_rename_ex(sf->sftp,
(char*)pv_old, len_old, (char*)pv_new, len_new, flags);
OUTPUT:
RETVAL
SSH2_NERROR
net_sf_mkdir(SSH2_SFTP* sf, SV* dir, int mode = 0777)
PREINIT:
const char* pv_dir;
STRLEN len_dir;
CODE:
pv_dir = SvPVbyte(dir, len_dir);
RETVAL = libssh2_sftp_mkdir_ex(sf->sftp, (char*)pv_dir, len_dir, mode);
OUTPUT:
RETVAL
SSH2_NERROR
net_sf_rmdir(SSH2_SFTP* sf, SV* dir)
PREINIT:
const char* pv_dir;
STRLEN len_dir;
CODE:
pv_dir = SvPVbyte(dir, len_dir);
RETVAL = libssh2_sftp_rmdir_ex(sf->sftp, (char*)pv_dir, len_dir);
OUTPUT:
RETVAL
void
net_sf_stat(SSH2_SFTP* sf, SV* path, int follow = 1)
PREINIT:
const char* pv_path;
STRLEN len_path;
int error;
LIBSSH2_SFTP_ATTRIBUTES attrs;
PPCODE:
pv_path = SvPVbyte(path, len_path);
error = libssh2_sftp_stat_ex(sf->sftp, (char*)pv_path, len_path,
(follow ? LIBSSH2_SFTP_STAT : LIBSSH2_SFTP_LSTAT),
&attrs);
if (error < 0)
XSRETURN_EMPTY;
XSRETURN_STAT_ATTRS(SvREFCNT_inc(path));
SSH2_NERROR
net_sf_setstat(SSH2_SFTP* sf, SV* path, ...)
PREINIT:
const char* pv_path;
STRLEN len_path;
LIBSSH2_SFTP_ATTRIBUTES attrs;
int i;
CODE:
pv_path = SvPVbyte(path, len_path);
Zero(&attrs, 1, LIBSSH2_SFTP_ATTRIBUTES);
/* read key/value pairs; cf. hv_from_attrs */
for (i = 2; i < items; i += 2) {
const char* key = SvPVbyte_nolen(ST(i));
if (i + 1 == items)
croak("%s::setstat: key without value", class);
if (0); /* prime the chain */
XLATATTR("size", filesize, SIZE)
XLATATTR("uid", uid, UIDGID)
XLATATTR("gid", gid, UIDGID)
XLATATTR("mode", permissions, PERMISSIONS)
XLATATTR("atime", atime, ACMODTIME)
XLATATTR("mtime", mtime, ACMODTIME)
else
croak("%s::setstat: unknown attribute: %s", class, key);
}
RETVAL = libssh2_sftp_stat_ex(sf->sftp, (char*)pv_path, len_path,
LIBSSH2_SFTP_SETSTAT, &attrs);
OUTPUT:
RETVAL
SSH2_NERROR
net_sf_symlink(SSH2_SFTP* sf, SV* path, SV* target)
PREINIT:
char *pv_path, *pv_target;
STRLEN len_path, len_target;
CODE:
pv_path = SvPVbyte(path, len_path);
pv_target = SvPVbyte(target, len_target);
RETVAL = libssh2_sftp_symlink_ex(sf->sftp,
pv_path, len_path,
pv_target, len_target,
LIBSSH2_SFTP_SYMLINK);
OUTPUT:
RETVAL
SV *
net_sf_readlink(SSH2_SFTP* sf, SV* path)
PREINIT:
const char* pv_path;
char* pv_link;
STRLEN len_path;
CODE:
debug("%s::DESTROY\n", class);
libssh2_sftp_close_handle(fi->handle);
SvREFCNT_dec(fi->sv_sf);
Safefree(fi);
SSH2_BYTES
net_fi_read(SSH2_FILE* fi, SV* buffer, size_t size)
PREINIT:
char* pv_buffer;
STRLEN len_buffer;
CODE:
sv_force_normal(buffer);
sv_setpvn_mg(buffer, "", 0);
SvPVbyte_force(buffer, len_buffer);
pv_buffer = sv_grow(buffer, size + 1);
RETVAL = libssh2_sftp_read(fi->handle, pv_buffer, size);
if (RETVAL < 0)
SvOK_off(buffer);
else {
SvPOK_only(buffer);
pv_buffer[RETVAL] = '\0';
SvCUR_set(buffer, RETVAL);
}
SvSETMAGIC(buffer);
OUTPUT:
RETVAL
SV *
net_fi_getc(SSH2_FILE* fi)
PREINIT:
char buffer[2];
int count;
CODE:
count = libssh2_sftp_read(fi->handle, buffer, 1);
if (count == 1) {
buffer[count] = '\0';
RETVAL = newSVpvn(buffer, count);
}
else
RETVAL = &PL_sv_undef;
OUTPUT:
RETVAL
SSH2_BYTES
net_fi_write(SSH2_FILE* fi, SV* buffer)
PREINIT:
const char* pv_buffer;
STRLEN len_buffer;
CODE:
sv_utf8_downgrade(buffer, 0);
pv_buffer = SvPVbyte(buffer, len_buffer);
RETVAL = libssh2_sftp_write(fi->handle, pv_buffer, len_buffer);
OUTPUT:
RETVAL
void
net_fi_stat(SSH2_FILE* fi)
PREINIT:
LIBSSH2_SFTP_ATTRIBUTES attrs;
PPCODE:
if (libssh2_sftp_fstat(fi->handle, &attrs))
XSRETURN_EMPTY;
XSRETURN_STAT_ATTRS(NULL/*name*/);
SSH2_NERROR
net_fi_setstat(SSH2_FILE* fi, ...)
PREINIT:
LIBSSH2_SFTP_ATTRIBUTES attrs;
int i;
CODE:
Zero(&attrs, 1, LIBSSH2_SFTP_ATTRIBUTES);
/* read key/value pairs; cf. hv_from_attrs */
for (i = 1; i < items; i += 2) {
const char* key = SvPVbyte_nolen(ST(i));
if (i + 1 == items)
croak("%s::setstat: key without value", class);
if (0); /* prime the chain */
XLATATTR("size", filesize, SIZE)
XLATATTR("uid", uid, UIDGID)
XLATATTR("gid", gid, UIDGID)
XLATATTR("mode", permissions, PERMISSIONS)
XLATATTR("atime", atime, ACMODTIME)
XLATATTR("mtime", mtime, ACMODTIME)
else
croak("%s::setstat: unknown attribute: %s", class, key);
}
RETVAL = libssh2_sftp_fsetstat(fi->handle, &attrs);
OUTPUT:
RETVAL
int
net_fi_seek(SSH2_FILE* fi, size_t offset)
CODE:
libssh2_sftp_seek64(fi->handle, offset);
RETVAL = 1;
OUTPUT:
RETVAL
SSH2_BYTES64
net_fi_tell(SSH2_FILE* fi)
CODE:
RETVAL = libssh2_sftp_tell64(fi->handle);
OUTPUT:
RETVAL
#undef class
MODULE = Net::SSH2 PACKAGE = Net::SSH2::Dir PREFIX = net_di_
PROTOTYPES: DISABLE
#define class "Net::SSH2::Dir"
void
net_di_DESTROY(SSH2_DIR* di)
CODE:
debug("%s::DESTROY\n", class);
libssh2_sftp_close_handle(di->handle);
SvREFCNT_dec(di->sv_sf);
Safefree(di);
void
net_di_read(SSH2_DIR* di)
PREINIT:
SV* buffer;
char* pv_buffer;
int count;
LIBSSH2_SFTP_ATTRIBUTES attrs;
PPCODE:
buffer = newSV(MAXPATHLEN + 1);
SvPOK_on(buffer);
pv_buffer = SvPVX(buffer);
count = libssh2_sftp_readdir(di->handle, pv_buffer, MAXPATHLEN, &attrs);
if (count <= 0) {
SvREFCNT_dec(buffer);
XSRETURN_EMPTY;
}
pv_buffer[count] = '\0';
SvCUR_set(buffer, count);
XSRETURN_STAT_ATTRS(buffer);
#undef class
MODULE = Net::SSH2 PACKAGE = Net::SSH2::PublicKey PREFIX = net_pk_
PROTOTYPES: DISABLE
#define class "Net::SSH2::PublicKey"
void
net_pk_DESTROY(SSH2_PUBLICKEY* pk)
CODE:
debug("%s::DESTROY\n", class);
libssh2_publickey_shutdown(pk->pkey);
SvREFCNT_dec(pk->sv_ss);
Safefree(pk);
SSH2_NERROR
net_pk_add(SSH2_PUBLICKEY* pk, SV* name, SV* blob, int overwrite, ...)
PREINIT:
const char* pv_name, * pv_blob;
STRLEN len_name, len_blob;
unsigned long num_attrs, i;
libssh2_publickey_attribute *attrs;
CODE:
pv_name = SvPVbyte(name, len_name);
pv_blob = SvPVbyte(blob, len_blob);
num_attrs = items - 4;
New(0, attrs, num_attrs, libssh2_publickey_attribute);
if (!attrs)
Perl_croak(aTHX_ "Out of memory!");
for (i = 0; i < num_attrs; ++i) {
HV* hv;
SV** tmp;
STRLEN len_tmp;
if (!SvROK(ST(i + 4)) || SvTYPE(SvRV(ST(i + 4))) != SVt_PVHV)
croak("%s::add: attribute %lu is not hash", class, i);
hv = (HV*)SvRV(ST(i + 4));
if (!(tmp = hv_fetch(hv, "name", 4, 0/*lval*/)) || !*tmp)
croak("%s::add: attribute %lu missing name", class, i);
attrs[i].name = SvPVbyte(*tmp, len_tmp);
attrs[i].name_len = len_tmp;
if ((tmp = hv_fetch(hv, "value", 5, 0/*lval*/)) && *tmp) {
attrs[i].value = SvPVbyte(*tmp, len_tmp);
attrs[i].value_len = len_tmp;
} else
attrs[i].value_len = 0;
if ((tmp = hv_fetch(hv, "mandatory", 9, 0/*lval*/)) && *tmp)
attrs[i].mandatory = (char)SvIV(*tmp);
else
attrs[i].mandatory = 0;
}
RETVAL = libssh2_publickey_add_ex(pk->pkey,
(const unsigned char *)pv_name, len_name,
(const unsigned char *)pv_blob, len_blob, overwrite, num_attrs, attrs);
Safefree(attrs);
OUTPUT:
RETVAL
SSH2_NERROR
net_pk_remove(SSH2_PUBLICKEY* pk, SV* name, SV* blob)
PREINIT:
const char* pv_name, * pv_blob;
STRLEN len_name, len_blob;
CODE:
pv_name = SvPVbyte(name, len_name);
pv_blob = SvPVbyte(blob, len_blob);
RETVAL = libssh2_publickey_remove_ex(pk->pkey,
(const unsigned char *)pv_name, len_name,
(const unsigned char *)pv_blob, len_blob);
OUTPUT:
RETVAL
void
net_pk_fetch(SSH2_PUBLICKEY* pk)
PREINIT:
unsigned long keys, i, j;
libssh2_publickey_list* list = NULL;
PPCODE:
if (!libssh2_publickey_list_fetch(pk->pkey, &keys, &list) || !list)
XSRETURN_EMPTY;
if (GIMME_V == G_ARRAY) {
EXTEND(SP, keys);
for (i = 0; i < keys; ++i) {
HV* hv = newHV();
AV* av = newAV();
hv_store(hv, "name", 4,
newSVpvn((char*)list[i].name, list[i].name_len), 0/*hash*/);
hv_store(hv, "blob", 4,
newSVpvn((char*)list[i].blob, list[i].blob_len), 0/*hash*/);
hv_store(hv, "attr", 4, newRV_noinc((SV*)av), 0/*hash*/);
av_extend(av, list[i].num_attrs - 1);
for (j = 0; j < list[i].num_attrs; ++j) {
HV* attr = newHV();
hv_store(attr, "name", 4, newSVpvn(list[i].attrs[j].name,
list[i].attrs[j].name_len), 0/*hash*/);
hv_store(attr, "value", 5, newSVpvn(list[i].attrs[j].value,
list[i].attrs[j].value_len), 0/*hash*/);
hv_store(attr, "mandatory", 9,
newSViv(list[i].attrs[j].mandatory), 0/*hash*/);
av_store(av, j, newRV_noinc((SV*)attr));
}
ST(i) = sv_2mortal(newRV_noinc((SV*)hv));
}
}
libssh2_publickey_list_free(pk->pkey, list);
if (GIMME_V == G_ARRAY)
XSRETURN(keys);
XSRETURN_UV(keys);
#undef class
MODULE = Net::SSH2 PACKAGE = Net::SSH2::KnownHosts PREFIX = net_kh_
PROTOTYPES: DISABLE
#define class "Net::SSH2::KnownHosts"
#if LIBSSH2_VERSION_NUM >= 0x010200
void
net_kh_DESTROY(SSH2_KNOWNHOSTS *kh)
CODE:
debug("%s::DESTROY\n", class);
libssh2_knownhost_free(kh->knownhosts);
SvREFCNT_dec(kh->sv_ss);
Safefree(kh);
SSH2_BYTES
net_kh_readfile(SSH2_KNOWNHOSTS *kh, SSH2_CHARP filename)
CODE:
RETVAL = libssh2_knownhost_readfile(kh->knownhosts, filename, LIBSSH2_KNOWNHOST_FILE_OPENSSH);
OUTPUT:
( run in 1.516 second using v1.01-cache-2.11-cpan-71847e10f99 )