Add libssh2_sftp_statvfs() and libssh2_sftp_fstatvfs()

These can be used to get file system statistics from servers that
support the statvfs@openssh.com and fstatvfs@openssh.com extensions.
This commit is contained in:
Joey Degges
2010-05-22 01:48:04 -07:00
committed by Peter Stuge
parent 667f4acda6
commit ed526a0e24
7 changed files with 359 additions and 0 deletions

View File

@@ -638,6 +638,16 @@ struct _LIBSSH2_SFTP
unsigned char *rename_s;
uint32_t rename_request_id;
/* State variables used in libssh2_sftp_fstatvfs() */
libssh2_nonblocking_states fstatvfs_state;
unsigned char *fstatvfs_packet;
uint32_t fstatvfs_request_id;
/* State variables used in libssh2_sftp_statvfs() */
libssh2_nonblocking_states statvfs_state;
unsigned char *statvfs_packet;
uint32_t statvfs_request_id;
/* State variables used in libssh2_sftp_mkdir() */
libssh2_nonblocking_states mkdir_state;
unsigned char *mkdir_packet;

View File

@@ -88,6 +88,9 @@
/* S_IFDIR */
#define LIBSSH2_SFTP_ATTR_PFILETYPE_DIR 0040000
#define SSH_FXE_STATVFS_ST_RDONLY 0x00000001
#define SSH_FXE_STATVFS_ST_NOSUID 0x00000002
static int sftp_close_handle(LIBSSH2_SFTP_HANDLE *handle);
/* sftp_attrsize
@@ -758,6 +761,14 @@ sftp_shutdown(LIBSSH2_SFTP *sftp)
LIBSSH2_FREE(session, sftp->rename_packet);
sftp->rename_packet = NULL;
}
if (sftp->fstatvfs_packet) {
LIBSSH2_FREE(session, sftp->fstatvfs_packet);
sftp->fstatvfs_packet = NULL;
}
if (sftp->statvfs_packet) {
LIBSSH2_FREE(session, sftp->statvfs_packet);
sftp->statvfs_packet = NULL;
}
if (sftp->mkdir_packet) {
LIBSSH2_FREE(session, sftp->mkdir_packet);
sftp->mkdir_packet = NULL;
@@ -1937,6 +1948,229 @@ libssh2_sftp_rename_ex(LIBSSH2_SFTP *sftp, const char *source_filename,
return rc;
}
/*
* sftp_fstatvfs
*
* Get file system statistics
*/
static int sftp_fstatvfs(LIBSSH2_SFTP_HANDLE *handle, LIBSSH2_SFTP_STATVFS *st)
{
LIBSSH2_SFTP *sftp = handle->sftp;
LIBSSH2_CHANNEL *channel = sftp->channel;
LIBSSH2_SESSION *session = channel->session;
size_t data_len;
/* 17 = packet_len(4) + packet_type(1) + request_id(4) + ext_len(4)
+ handle_len (4) */
/* 20 = strlen ("fstatvfs@openssh.com") */
ssize_t packet_len = handle->handle_len + 20 + 17;
unsigned char *packet, *s, *data;
int rc;
unsigned int flag;
if (sftp->fstatvfs_state == libssh2_NB_state_idle) {
_libssh2_debug(session, LIBSSH2_TRACE_SFTP,
"Getting file system statistics");
s = packet = LIBSSH2_ALLOC(session, packet_len);
if (!packet) {
return _libssh2_error(session, LIBSSH2_ERROR_ALLOC,
"Unable to allocate memory for FXP_EXTENDED "
"packet");
}
_libssh2_store_u32(&s, packet_len - 4);
*(s++) = SSH_FXP_EXTENDED;
sftp->fstatvfs_request_id = sftp->request_id++;
_libssh2_store_u32(&s, sftp->fstatvfs_request_id);
_libssh2_store_str(&s, "fstatvfs@openssh.com", 20);
_libssh2_store_str(&s, handle->handle, handle->handle_len);
sftp->fstatvfs_state = libssh2_NB_state_created;
}
else {
packet = sftp->fstatvfs_packet;
}
if (sftp->fstatvfs_state == libssh2_NB_state_created) {
rc = _libssh2_channel_write(channel, 0, (char *) packet, packet_len);
if (rc == LIBSSH2_ERROR_EAGAIN || (0 <= rc && rc < packet_len)) {
sftp->fstatvfs_packet = packet;
return LIBSSH2_ERROR_EAGAIN;
}
LIBSSH2_FREE(session, packet);
sftp->fstatvfs_packet = NULL;
if (rc < 0) {
sftp->fstatvfs_state = libssh2_NB_state_idle;
return _libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
"_libssh2_channel_write() failed");
}
sftp->fstatvfs_state = libssh2_NB_state_sent;
}
rc = sftp_packet_require(sftp, SSH_FXP_EXTENDED_REPLY,
sftp->fstatvfs_request_id, &data, &data_len);
if (rc == LIBSSH2_ERROR_EAGAIN) {
return rc;
} else if (rc) {
sftp->fstatvfs_state = libssh2_NB_state_idle;
return _libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT,
"Timeout waiting for status message");
} else if (data_len < 93) {
LIBSSH2_FREE(session, data);
sftp->fstatvfs_state = libssh2_NB_state_idle;
return _libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL,
"SFTP Protocol Error: short response");
}
sftp->fstatvfs_state = libssh2_NB_state_idle;
st->f_bsize = _libssh2_ntohu64(data + 5);
st->f_frsize = _libssh2_ntohu64(data + 13);
st->f_blocks = _libssh2_ntohu64(data + 21);
st->f_bfree = _libssh2_ntohu64(data + 29);
st->f_bavail = _libssh2_ntohu64(data + 37);
st->f_files = _libssh2_ntohu64(data + 45);
st->f_ffree = _libssh2_ntohu64(data + 53);
st->f_favail = _libssh2_ntohu64(data + 61);
st->f_fsid = _libssh2_ntohu64(data + 69);
flag = _libssh2_ntohu64(data + 77);
st->f_namemax = _libssh2_ntohu64(data + 85);
st->f_flag = (flag & SSH_FXE_STATVFS_ST_RDONLY)
? LIBSSH2_SFTP_ST_RDONLY : 0;
st->f_flag |= (flag & SSH_FXE_STATVFS_ST_NOSUID)
? LIBSSH2_SFTP_ST_NOSUID : 0;
LIBSSH2_FREE(session, data);
return 0;
}
/* libssh2_sftp_fstatvfs
* Get filesystem space and inode utilization (requires fstatvfs@openssh.com
* support on the server)
*/
LIBSSH2_API int
libssh2_sftp_fstatvfs(LIBSSH2_SFTP_HANDLE *handle, LIBSSH2_SFTP_STATVFS *st)
{
int rc;
BLOCK_ADJUST(rc, handle->sftp->channel->session, sftp_fstatvfs(handle, st));
return rc;
}
/*
* sftp_statvfs
*
* Get file system statistics
*/
static int sftp_statvfs(LIBSSH2_SFTP *sftp, const char *path,
unsigned int path_len, LIBSSH2_SFTP_STATVFS *st)
{
LIBSSH2_CHANNEL *channel = sftp->channel;
LIBSSH2_SESSION *session = channel->session;
size_t data_len;
/* 17 = packet_len(4) + packet_type(1) + request_id(4) + ext_len(4)
+ path_len (4) */
/* 19 = strlen ("statvfs@openssh.com") */
ssize_t packet_len = path_len + 19 + 17;
unsigned char *packet, *s, *data;
int rc;
unsigned int flag;
if (sftp->statvfs_state == libssh2_NB_state_idle) {
_libssh2_debug(session, LIBSSH2_TRACE_SFTP,
"Getting file system statistics of %s", path);
s = packet = LIBSSH2_ALLOC(session, packet_len);
if (!packet) {
return _libssh2_error(session, LIBSSH2_ERROR_ALLOC,
"Unable to allocate memory for FXP_EXTENDED "
"packet");
}
_libssh2_store_u32(&s, packet_len - 4);
*(s++) = SSH_FXP_EXTENDED;
sftp->statvfs_request_id = sftp->request_id++;
_libssh2_store_u32(&s, sftp->statvfs_request_id);
_libssh2_store_str(&s, "statvfs@openssh.com", 19);
_libssh2_store_str(&s, path, path_len);
sftp->statvfs_state = libssh2_NB_state_created;
}
else {
packet = sftp->statvfs_packet;
}
if (sftp->statvfs_state == libssh2_NB_state_created) {
rc = _libssh2_channel_write(channel, 0, (char *) packet, packet_len);
if (rc == LIBSSH2_ERROR_EAGAIN || (0 <= rc && rc < packet_len)) {
sftp->statvfs_packet = packet;
return LIBSSH2_ERROR_EAGAIN;
}
LIBSSH2_FREE(session, packet);
sftp->statvfs_packet = NULL;
if (rc < 0) {
sftp->statvfs_state = libssh2_NB_state_idle;
return _libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
"_libssh2_channel_write() failed");
}
sftp->statvfs_state = libssh2_NB_state_sent;
}
rc = sftp_packet_require(sftp, SSH_FXP_EXTENDED_REPLY,
sftp->statvfs_request_id, &data, &data_len);
if (rc == LIBSSH2_ERROR_EAGAIN) {
return rc;
} else if (rc) {
sftp->statvfs_state = libssh2_NB_state_idle;
return _libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT,
"Timeout waiting for status message");
} else if (data_len < 93) {
LIBSSH2_FREE(session, data);
sftp->fstatvfs_state = libssh2_NB_state_idle;
return _libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL,
"SFTP Protocol Error: short response");
}
sftp->statvfs_state = libssh2_NB_state_idle;
st->f_bsize = _libssh2_ntohu64(data + 5);
st->f_frsize = _libssh2_ntohu64(data + 13);
st->f_blocks = _libssh2_ntohu64(data + 21);
st->f_bfree = _libssh2_ntohu64(data + 29);
st->f_bavail = _libssh2_ntohu64(data + 37);
st->f_files = _libssh2_ntohu64(data + 45);
st->f_ffree = _libssh2_ntohu64(data + 53);
st->f_favail = _libssh2_ntohu64(data + 61);
st->f_fsid = _libssh2_ntohu64(data + 69);
flag = _libssh2_ntohu64(data + 77);
st->f_namemax = _libssh2_ntohu64(data + 85);
st->f_flag = (flag & SSH_FXE_STATVFS_ST_RDONLY)
? LIBSSH2_SFTP_ST_RDONLY : 0;
st->f_flag |= (flag & SSH_FXE_STATVFS_ST_NOSUID)
? LIBSSH2_SFTP_ST_NOSUID : 0;
LIBSSH2_FREE(session, data);
return 0;
}
/* libssh2_sftp_statvfs_ex
* Get filesystem space and inode utilization (requires statvfs@openssh.com
* support on the server)
*/
LIBSSH2_API int
libssh2_sftp_statvfs_ex(LIBSSH2_SFTP *sftp, const char *path,
unsigned int path_len, LIBSSH2_SFTP_STATVFS *st)
{
int rc;
BLOCK_ADJUST(rc, sftp->channel->session, sftp_statvfs(sftp, path, path_len,
st));
return rc;
}
/*
* sftp_mkdir
*