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

@ -113,6 +113,7 @@ dist_man_MANS = \
libssh2_sftp_fsetstat.3 \
libssh2_sftp_fstat.3 \
libssh2_sftp_fstat_ex.3 \
libssh2_sftp_fstatvfs.3 \
libssh2_sftp_init.3 \
libssh2_sftp_last_error.3 \
libssh2_sftp_lstat.3 \
@ -136,6 +137,8 @@ dist_man_MANS = \
libssh2_sftp_shutdown.3 \
libssh2_sftp_stat.3 \
libssh2_sftp_stat_ex.3 \
libssh2_sftp_statvfs.3 \
libssh2_sftp_statvfs_ex.3 \
libssh2_sftp_symlink.3 \
libssh2_sftp_symlink_ex.3 \
libssh2_sftp_tell.3 \

View File

@ -0,0 +1 @@
.so man3/libssh2_sftp_statvfs.3

View File

@ -0,0 +1,81 @@
.TH libssh2_sftp_statvfs 3 "22 May 2010" "libssh2 1.2.6" "libssh2 manual"
.SH NAME
libssh2_sftp_statvfs, libssh2_sftp_fstatvfs - get file system statistics
.SH SYNOPSIS
.nf
#include <libssh2.h>
#include <libssh2_sftp.h>
int
libssh2_sftp_statvfs_ex(LIBSSH2_SFTP *sftp, const char *path,
unsigned int path_len, LIBSSH2_SFTP_STATVFS *st);
#define libssh2_sftp_statvfs(sftp, path, st) \\
libssh2_sftp_statvfs_ex((sftp), (path), strlen(path), (st))
int
libssh2_sftp_fstatvfs(LIBSSH2_SFTP_HANDLE *handle,
LIBSSH2_SFTP_STATVFS *st)
.fi
.SH DESCRIPTION
These functions provide statvfs(2)-like operations and require
statvfs@openssh.com and fstatvfs@openssh.com extension support on the server.
\fIsftp\fP - SFTP instance as returned by
.BR libssh2_sftp_init(3)
\fIhandle\fP - SFTP File Handle as returned by
.BR libssh2_sftp_open_ex(3)
\fIpath\fP - full path of any file within the mounted file system.
\fIpath_len\fP - length of the full path.
\fIst\fP - Pointer to a LIBSSH2_SFTP_STATVFS structure to place file system
statistics into.
.SH DATA TYPES
LIBSSH2_SFTP_STATVFS is a typedefed struct that is defined as below
.nf
struct _LIBSSH2_SFTP_STATVFS {
libssh2_uint64_t f_bsize; /* file system block size */
libssh2_uint64_t f_frsize; /* fragment size */
libssh2_uint64_t f_blocks; /* size of fs in f_frsize units */
libssh2_uint64_t f_bfree; /* # free blocks */
libssh2_uint64_t f_bavail; /* # free blocks for non-root */
libssh2_uint64_t f_files; /* # inodes */
libssh2_uint64_t f_ffree; /* # free inodes */
libssh2_uint64_t f_favail; /* # free inodes for non-root */
libssh2_uint64_t f_fsid; /* file system ID */
libssh2_uint64_t f_flag; /* mount flags */
libssh2_uint64_t f_namemax; /* maximum filename length */
};
.fi
It is unspecified whether all members of the returned struct have meaningful
values on all file systems.
The field \fIf_flag\fP is a bit mask. Bits are defined as follows:
.IP LIBSSH2_SFTP_ST_RDONLY
Read-only file system.
.IP LIBSSH2_SFTP_ST_NOSUID
Set-user-ID/set-group-ID bits are ignored by \fBexec\fP(3).
.SH RETURN VALUE
Returns 0 on success or negative on failure. If used in non-blocking mode, it
returns LIBSSH2_ERROR_EAGAIN when it would otherwise block. While
LIBSSH2_ERROR_EAGAIN is a negative number, it isn't really a failure per se.
.SH ERRORS
\fILIBSSH2_ERROR_ALLOC\fP - An internal memory allocation call failed.
\fILIBSSH2_ERROR_SOCKET_SEND\fP - Unable to send data on socket.
\fILIBSSH2_ERROR_SOCKET_TIMEOUT\fP -
\fILIBSSH2_ERROR_SFTP_PROTOCOL\fP - An invalid SFTP protocol response was
received on the socket, or an SFTP operation caused an errorcode to be returned
by the server.
.SH AVAILABILITY
Added in libssh2 1.2.6
.SH SEE ALSO
.BR libssh2_sftp_open_ex(3)

View File

@ -0,0 +1 @@
.so man3/libssh2_sftp_statvfs.3

View File

@ -59,6 +59,7 @@ extern "C" {
typedef struct _LIBSSH2_SFTP LIBSSH2_SFTP;
typedef struct _LIBSSH2_SFTP_HANDLE LIBSSH2_SFTP_HANDLE;
typedef struct _LIBSSH2_SFTP_ATTRIBUTES LIBSSH2_SFTP_ATTRIBUTES;
typedef struct _LIBSSH2_SFTP_STATVFS LIBSSH2_SFTP_STATVFS;
/* Flags for open_ex() */
#define LIBSSH2_SFTP_OPENFILE 0
@ -86,6 +87,10 @@ typedef struct _LIBSSH2_SFTP_ATTRIBUTES LIBSSH2_SFTP_ATTRIBUTES;
#define LIBSSH2_SFTP_ATTR_ACMODTIME 0x00000008
#define LIBSSH2_SFTP_ATTR_EXTENDED 0x80000000
/* SFTP statvfs flag bits */
#define LIBSSH2_SFTP_ST_RDONLY 0x00000001
#define LIBSSH2_SFTP_ST_NOSUID 0x00000002
struct _LIBSSH2_SFTP_ATTRIBUTES {
/* If flags & ATTR_* bit is set, then the value in this struct will be
* meaningful Otherwise it should be ignored
@ -98,6 +103,20 @@ struct _LIBSSH2_SFTP_ATTRIBUTES {
unsigned long atime, mtime;
};
struct _LIBSSH2_SFTP_STATVFS {
libssh2_uint64_t f_bsize; /* file system block size */
libssh2_uint64_t f_frsize; /* fragment size */
libssh2_uint64_t f_blocks; /* size of fs in f_frsize units */
libssh2_uint64_t f_bfree; /* # free blocks */
libssh2_uint64_t f_bavail; /* # free blocks for non-root */
libssh2_uint64_t f_files; /* # inodes */
libssh2_uint64_t f_ffree; /* # free inodes */
libssh2_uint64_t f_favail; /* # free inodes for non-root */
libssh2_uint64_t f_fsid; /* file system ID */
libssh2_uint64_t f_flag; /* mount flags */
libssh2_uint64_t f_namemax; /* maximum filename length */
};
/* SFTP filetypes */
#define LIBSSH2_SFTP_TYPE_REGULAR 1
#define LIBSSH2_SFTP_TYPE_DIRECTORY 2
@ -269,6 +288,16 @@ LIBSSH2_API int libssh2_sftp_unlink_ex(LIBSSH2_SFTP *sftp,
#define libssh2_sftp_unlink(sftp, filename) \
libssh2_sftp_unlink_ex((sftp), (filename), strlen(filename))
LIBSSH2_API int libssh2_sftp_fstatvfs(LIBSSH2_SFTP_HANDLE *handle,
LIBSSH2_SFTP_STATVFS *st);
LIBSSH2_API int libssh2_sftp_statvfs_ex(LIBSSH2_SFTP *sftp,
const char *path,
unsigned int path_len,
LIBSSH2_SFTP_STATVFS *st);
#define libssh2_sftp_statvfs(sftp, path, st) \
libssh2_sftp_statvfs_ex((sftp), (path), strlen(path), (st))
LIBSSH2_API int libssh2_sftp_mkdir_ex(LIBSSH2_SFTP *sftp,
const char *path,
unsigned int path_len, long mode);

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
*