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:
parent
667f4acda6
commit
ed526a0e24
@ -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 \
|
||||
|
1
docs/libssh2_sftp_fstatvfs.3
Normal file
1
docs/libssh2_sftp_fstatvfs.3
Normal file
@ -0,0 +1 @@
|
||||
.so man3/libssh2_sftp_statvfs.3
|
81
docs/libssh2_sftp_statvfs.3
Normal file
81
docs/libssh2_sftp_statvfs.3
Normal 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)
|
1
docs/libssh2_sftp_statvfs_ex.3
Normal file
1
docs/libssh2_sftp_statvfs_ex.3
Normal file
@ -0,0 +1 @@
|
||||
.so man3/libssh2_sftp_statvfs.3
|
@ -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);
|
||||
|
@ -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;
|
||||
|
234
src/sftp.c
234
src/sftp.c
@ -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
|
||||
*
|
||||
|
Loading…
Reference in New Issue
Block a user