summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDamien Miller <djm@mindrot.org>2008-05-19 14:53:33 +1000
committerDamien Miller <djm@mindrot.org>2008-05-19 14:53:33 +1000
commitd671e5a978efd5ba949d3fdcd03f728dcd68c636 (patch)
treef63127fe29690fbe2c00f7b50d7807dc24288e29
parent354c48c641e7fbdc273ee8e1239ff71d73a1ec3e (diff)
downloadopenssh-git-d671e5a978efd5ba949d3fdcd03f728dcd68c636.tar.gz
- djm@cvs.openbsd.org 2008/04/18 12:32:11
[sftp-client.c sftp-client.h sftp-server.c sftp.1 sftp.c sftp.h] introduce sftp extension methods statvfs@openssh.com and fstatvfs@openssh.com that implement statvfs(2)-like operations, based on a patch from miklos AT szeredi.hu (bz#1399) also add a "df" command to the sftp client that uses the statvfs@openssh.com to produce a df(1)-like display of filesystem space and inode utilisation ok markus@
-rw-r--r--ChangeLog11
-rw-r--r--sftp-client.c120
-rw-r--r--sftp-client.h6
-rw-r--r--sftp-server.c75
-rw-r--r--sftp.124
-rw-r--r--sftp.c112
-rw-r--r--sftp.h6
7 files changed, 339 insertions, 15 deletions
diff --git a/ChangeLog b/ChangeLog
index b32f93f0..eba49fee 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -21,6 +21,15 @@
Use arc4random_uniform() when the desired random number upper bound
is not a power of two
ok deraadt@ millert@
+ - djm@cvs.openbsd.org 2008/04/18 12:32:11
+ [sftp-client.c sftp-client.h sftp-server.c sftp.1 sftp.c sftp.h]
+ introduce sftp extension methods statvfs@openssh.com and
+ fstatvfs@openssh.com that implement statvfs(2)-like operations,
+ based on a patch from miklos AT szeredi.hu (bz#1399)
+ also add a "df" command to the sftp client that uses the
+ statvfs@openssh.com to produce a df(1)-like display of filesystem
+ space and inode utilisation
+ ok markus@
20080403
- (djm) [openbsd-compat/bsd-poll.c] Include stdlib.h to avoid compile-
@@ -3881,4 +3890,4 @@
OpenServer 6 and add osr5bigcrypt support so when someone migrates
passwords between UnixWare and OpenServer they will still work. OK dtucker@
-$Id: ChangeLog,v 1.4910 2008/05/19 04:50:00 djm Exp $
+$Id: ChangeLog,v 1.4911 2008/05/19 04:53:33 djm Exp $
diff --git a/sftp-client.c b/sftp-client.c
index 69c63778..1e54348b 100644
--- a/sftp-client.c
+++ b/sftp-client.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: sftp-client.c,v 1.81 2008/03/23 12:54:01 djm Exp $ */
+/* $OpenBSD: sftp-client.c,v 1.82 2008/04/18 12:32:11 djm Exp $ */
/*
* Copyright (c) 2001-2004 Damien Miller <djm@openbsd.org>
*
@@ -24,6 +24,7 @@
#include <sys/types.h>
#include <sys/param.h>
+#include <sys/statvfs.h>
#include "openbsd-compat/sys-queue.h"
#ifdef HAVE_SYS_STAT_H
# include <sys/stat.h>
@@ -65,7 +66,9 @@ struct sftp_conn {
u_int num_requests;
u_int version;
u_int msg_id;
-#define SFTP_EXT_POSIX_RENAME 1
+#define SFTP_EXT_POSIX_RENAME 0x00000001
+#define SFTP_EXT_STATVFS 0x00000002
+#define SFTP_EXT_FSTATVFS 0x00000004
u_int exts;
};
@@ -238,6 +241,56 @@ get_decode_stat(int fd, u_int expected_id, int quiet)
return(a);
}
+static int
+get_decode_statvfs(int fd, struct statvfs *st, u_int expected_id, int quiet)
+{
+ Buffer msg;
+ u_int type, id, flag;
+
+ buffer_init(&msg);
+ get_msg(fd, &msg);
+
+ type = buffer_get_char(&msg);
+ id = buffer_get_int(&msg);
+
+ debug3("Received statvfs reply T:%u I:%u", type, id);
+ if (id != expected_id)
+ fatal("ID mismatch (%u != %u)", id, expected_id);
+ if (type == SSH2_FXP_STATUS) {
+ int status = buffer_get_int(&msg);
+
+ if (quiet)
+ debug("Couldn't statvfs: %s", fx2txt(status));
+ else
+ error("Couldn't statvfs: %s", fx2txt(status));
+ buffer_free(&msg);
+ return -1;
+ } else if (type != SSH2_FXP_EXTENDED_REPLY) {
+ fatal("Expected SSH2_FXP_EXTENDED_REPLY(%u) packet, got %u",
+ SSH2_FXP_EXTENDED_REPLY, type);
+ }
+
+ bzero(st, sizeof(*st));
+ st->f_bsize = buffer_get_int(&msg);
+ st->f_frsize = buffer_get_int(&msg);
+ st->f_blocks = buffer_get_int64(&msg);
+ st->f_bfree = buffer_get_int64(&msg);
+ st->f_bavail = buffer_get_int64(&msg);
+ st->f_files = buffer_get_int64(&msg);
+ st->f_ffree = buffer_get_int64(&msg);
+ st->f_favail = buffer_get_int64(&msg);
+ st->f_fsid = buffer_get_int(&msg);
+ flag = buffer_get_int(&msg);
+ st->f_namemax = buffer_get_int(&msg);
+
+ st->f_flag = (flag & SSH2_FXE_STATVFS_ST_RDONLY) ? ST_RDONLY : 0;
+ st->f_flag |= (flag & SSH2_FXE_STATVFS_ST_NOSUID) ? ST_NOSUID : 0;
+
+ buffer_free(&msg);
+
+ return 0;
+}
+
struct sftp_conn *
do_init(int fd_in, int fd_out, u_int transfer_buflen, u_int num_requests)
{
@@ -272,8 +325,15 @@ do_init(int fd_in, int fd_out, u_int transfer_buflen, u_int num_requests)
char *value = buffer_get_string(&msg, NULL);
debug2("Init extension: \"%s\"", name);
- if (strcmp(name, "posix-rename@openssh.com") == 0)
+ if (strcmp(name, "posix-rename@openssh.com") == 0 &&
+ strcmp(value, "1") == 0)
exts |= SFTP_EXT_POSIX_RENAME;
+ if (strcmp(name, "statvfs@openssh.com") == 0 &&
+ strcmp(value, "1") == 0)
+ exts |= SFTP_EXT_STATVFS;
+ if (strcmp(name, "fstatvfs@openssh.com") == 0 &&
+ strcmp(value, "1") == 0)
+ exts |= SFTP_EXT_FSTATVFS;
xfree(name);
xfree(value);
}
@@ -749,6 +809,60 @@ do_readlink(struct sftp_conn *conn, char *path)
}
#endif
+int
+do_statvfs(struct sftp_conn *conn, const char *path, struct statvfs *st,
+ int quiet)
+{
+ Buffer msg;
+ u_int id;
+
+ if ((conn->exts & SFTP_EXT_STATVFS) == 0) {
+ error("Server does not support statvfs@openssh.com extension");
+ return -1;
+ }
+
+ id = conn->msg_id++;
+
+ buffer_init(&msg);
+ buffer_clear(&msg);
+ buffer_put_char(&msg, SSH2_FXP_EXTENDED);
+ buffer_put_int(&msg, id);
+ buffer_put_cstring(&msg, "statvfs@openssh.com");
+ buffer_put_cstring(&msg, path);
+ send_msg(conn->fd_out, &msg);
+ buffer_free(&msg);
+
+ return get_decode_statvfs(conn->fd_in, st, id, quiet);
+}
+
+#ifdef notyet
+int
+do_fstatvfs(struct sftp_conn *conn, const char *handle, u_int handle_len,
+ struct statvfs *st, int quiet)
+{
+ Buffer msg;
+ u_int id;
+
+ if ((conn->exts & SFTP_EXT_FSTATVFS) == 0) {
+ error("Server does not support fstatvfs@openssh.com extension");
+ return -1;
+ }
+
+ id = conn->msg_id++;
+
+ buffer_init(&msg);
+ buffer_clear(&msg);
+ buffer_put_char(&msg, SSH2_FXP_EXTENDED);
+ buffer_put_int(&msg, id);
+ buffer_put_cstring(&msg, "fstatvfs@openssh.com");
+ buffer_put_string(&msg, handle, handle_len);
+ send_msg(conn->fd_out, &msg);
+ buffer_free(&msg);
+
+ return get_decode_statvfs(conn->fd_in, st, id, quiet);
+}
+#endif
+
static void
send_read_request(int fd_out, u_int id, u_int64_t offset, u_int len,
char *handle, u_int handle_len)
diff --git a/sftp-client.h b/sftp-client.h
index fd0630e9..b102e118 100644
--- a/sftp-client.h
+++ b/sftp-client.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: sftp-client.h,v 1.15 2008/01/11 07:22:28 chl Exp $ */
+/* $OpenBSD: sftp-client.h,v 1.16 2008/04/18 12:32:11 djm Exp $ */
/*
* Copyright (c) 2001-2004 Damien Miller <djm@openbsd.org>
@@ -70,6 +70,10 @@ int do_fsetstat(struct sftp_conn *, char *, u_int, Attrib *);
/* Canonicalise 'path' - caller must free result */
char *do_realpath(struct sftp_conn *, char *);
+/* Get statistics for filesystem hosting file at "path" */
+struct statvfs;
+int do_statvfs(struct sftp_conn *, const char *, struct statvfs *, int);
+
/* Rename 'oldpath' to 'newpath' */
int do_rename(struct sftp_conn *, char *, char *);
diff --git a/sftp-server.c b/sftp-server.c
index d9549f5b..300fd5cf 100644
--- a/sftp-server.c
+++ b/sftp-server.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: sftp-server.c,v 1.78 2008/02/27 20:21:15 djm Exp $ */
+/* $OpenBSD: sftp-server.c,v 1.79 2008/04/18 12:32:11 djm Exp $ */
/*
* Copyright (c) 2000-2004 Markus Friedl. All rights reserved.
*
@@ -23,6 +23,8 @@
#ifdef HAVE_SYS_TIME_H
# include <sys/time.h>
#endif
+#include <sys/mount.h>
+#include <sys/statvfs.h>
#include <dirent.h>
#include <errno.h>
@@ -475,6 +477,33 @@ send_attrib(u_int32_t id, const Attrib *a)
buffer_free(&msg);
}
+static void
+send_statvfs(u_int32_t id, struct statvfs *st)
+{
+ Buffer msg;
+ u_int64_t flag;
+
+ flag = (st->f_flag & ST_RDONLY) ? SSH2_FXE_STATVFS_ST_RDONLY : 0;
+ flag |= (st->f_flag & ST_NOSUID) ? SSH2_FXE_STATVFS_ST_NOSUID : 0;
+
+ buffer_init(&msg);
+ buffer_put_char(&msg, SSH2_FXP_EXTENDED_REPLY);
+ buffer_put_int(&msg, id);
+ buffer_put_int(&msg, st->f_bsize);
+ buffer_put_int(&msg, st->f_frsize);
+ buffer_put_int64(&msg, st->f_blocks);
+ buffer_put_int64(&msg, st->f_bfree);
+ buffer_put_int64(&msg, st->f_bavail);
+ buffer_put_int64(&msg, st->f_files);
+ buffer_put_int64(&msg, st->f_ffree);
+ buffer_put_int64(&msg, st->f_favail);
+ buffer_put_int(&msg, st->f_fsid);
+ buffer_put_int(&msg, flag);
+ buffer_put_int(&msg, st->f_namemax);
+ send_msg(&msg);
+ buffer_free(&msg);
+}
+
/* parse incoming */
static void
@@ -490,6 +519,10 @@ process_init(void)
/* POSIX rename extension */
buffer_put_cstring(&msg, "posix-rename@openssh.com");
buffer_put_cstring(&msg, "1"); /* version */
+ buffer_put_cstring(&msg, "statvfs@openssh.com");
+ buffer_put_cstring(&msg, "1"); /* version */
+ buffer_put_cstring(&msg, "fstatvfs@openssh.com");
+ buffer_put_cstring(&msg, "1"); /* version */
send_msg(&msg);
buffer_free(&msg);
}
@@ -1100,6 +1133,42 @@ process_extended_posix_rename(u_int32_t id)
}
static void
+process_extended_statvfs(u_int32_t id)
+{
+ char *path;
+ struct statvfs st;
+
+ path = get_string(NULL);
+ debug3("request %u: statfs", id);
+ logit("statfs \"%s\"", path);
+
+ if (statvfs(path, &st) != 0)
+ send_status(id, errno_to_portable(errno));
+ else
+ send_statvfs(id, &st);
+ xfree(path);
+}
+
+static void
+process_extended_fstatvfs(u_int32_t id)
+{
+ int handle, fd;
+ struct statvfs st;
+
+ handle = get_handle();
+ debug("request %u: fstatvfs \"%s\" (handle %u)",
+ id, handle_to_name(handle), handle);
+ if ((fd = handle_to_fd(handle)) < 0) {
+ send_status(id, SSH2_FX_FAILURE);
+ return;
+ }
+ if (fstatvfs(fd, &st) != 0)
+ send_status(id, errno_to_portable(errno));
+ else
+ send_statvfs(id, &st);
+}
+
+static void
process_extended(void)
{
u_int32_t id;
@@ -1109,6 +1178,10 @@ process_extended(void)
request = get_string(NULL);
if (strcmp(request, "posix-rename@openssh.com") == 0)
process_extended_posix_rename(id);
+ else if (strcmp(request, "statvfs@openssh.com") == 0)
+ process_extended_statvfs(id);
+ else if (strcmp(request, "fstatvfs@openssh.com") == 0)
+ process_extended_fstatvfs(id);
else
send_status(id, SSH2_FX_OP_UNSUPPORTED); /* MUST */
xfree(request);
diff --git a/sftp.1 b/sftp.1
index 1f517a40..f34f5885 100644
--- a/sftp.1
+++ b/sftp.1
@@ -1,4 +1,4 @@
-.\" $OpenBSD: sftp.1,v 1.64 2007/05/31 19:20:16 jmc Exp $
+.\" $OpenBSD: sftp.1,v 1.65 2008/04/18 12:32:11 djm Exp $
.\"
.\" Copyright (c) 2001 Damien Miller. All rights reserved.
.\"
@@ -22,7 +22,7 @@
.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
.\"
-.Dd $Mdocdate: May 31 2007 $
+.Dd $Mdocdate: April 18 2008 $
.Dt SFTP 1
.Os
.Sh NAME
@@ -112,7 +112,7 @@ will abort if any of the following
commands fail:
.Ic get , put , rename , ln ,
.Ic rm , mkdir , chdir , ls ,
-.Ic lchdir , chmod , chown , chgrp , lpwd
+.Ic lchdir , chmod , chown , chgrp , lpwd, df,
and
.Ic lmkdir .
Termination on error can be suppressed on a command by command basis by
@@ -272,6 +272,24 @@ may contain
characters and may match multiple files.
.Ar own
must be a numeric UID.
+.It Xo Ic df
+.Op Fl hi
+.Op Ar path
+.Xc
+Display usage information for the filesystem holding the current directory
+(or
+.Ar path
+if specified).
+If the
+.Fl h
+flag is specified, the capacity information will be displayed using
+"human-readable" suffixes.
+The
+.Fl i
+flag requests display of inode information in addition to capacity information.
+This command is only supported on servers that implement the
+.Dq statvfs@openssh.com
+extension.
.It Ic exit
Quit
.Nm sftp .
diff --git a/sftp.c b/sftp.c
index 861c3db0..0745baf0 100644
--- a/sftp.c
+++ b/sftp.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: sftp.c,v 1.99 2008/01/20 00:38:30 djm Exp $ */
+/* $OpenBSD: sftp.c,v 1.100 2008/04/18 12:32:11 djm Exp $ */
/*
* Copyright (c) 2001-2004 Damien Miller <djm@openbsd.org>
*
@@ -25,6 +25,7 @@
#include <sys/param.h>
#include <sys/socket.h>
#include <sys/wait.h>
+#include <sys/statvfs.h>
#include <ctype.h>
#include <errno.h>
@@ -42,6 +43,7 @@ typedef void EditLine;
#include <stdio.h>
#include <string.h>
#include <unistd.h>
+#include <util.h>
#include <stdarg.h>
#include "xmalloc.h"
@@ -104,6 +106,7 @@ extern char *__progname;
#define I_CHGRP 2
#define I_CHMOD 3
#define I_CHOWN 4
+#define I_DF 24
#define I_GET 5
#define I_HELP 6
#define I_LCHDIR 7
@@ -136,6 +139,7 @@ static const struct CMD cmds[] = {
{ "chgrp", I_CHGRP },
{ "chmod", I_CHMOD },
{ "chown", I_CHOWN },
+ { "df", I_DF },
{ "dir", I_LS },
{ "exit", I_QUIT },
{ "get", I_GET },
@@ -200,6 +204,8 @@ help(void)
printf("chgrp grp path Change group of file 'path' to 'grp'\n");
printf("chmod mode path Change permissions of file 'path' to 'mode'\n");
printf("chown own path Change owner of file 'path' to 'own'\n");
+ printf("df [path] Display statistics for current directory or\n");
+ printf(" filesystem containing 'path'\n");
printf("help Display this help text\n");
printf("get remote-path [local-path] Download file\n");
printf("lls [ls-options [path]] Display local directory listing\n");
@@ -422,6 +428,33 @@ parse_ls_flags(char **argv, int argc, int *lflag)
}
static int
+parse_df_flags(const char *cmd, char **argv, int argc, int *hflag, int *iflag)
+{
+ extern int optind, optreset, opterr;
+ int ch;
+
+ optind = optreset = 1;
+ opterr = 0;
+
+ *hflag = *iflag = 0;
+ while ((ch = getopt(argc, argv, "hi")) != -1) {
+ switch (ch) {
+ case 'h':
+ *hflag = 1;
+ break;
+ case 'i':
+ *iflag = 1;
+ break;
+ default:
+ error("%s: Invalid flag -%c", cmd, ch);
+ return -1;
+ }
+ }
+
+ return optind;
+}
+
+static int
is_dir(char *path)
{
struct stat sb;
@@ -797,6 +830,56 @@ do_globbed_ls(struct sftp_conn *conn, char *path, char *strip_path,
return (0);
}
+static int
+do_df(struct sftp_conn *conn, char *path, int hflag, int iflag)
+{
+ struct statvfs st;
+ char s_used[FMT_SCALED_STRSIZE];
+ char s_avail[FMT_SCALED_STRSIZE];
+ char s_root[FMT_SCALED_STRSIZE];
+ char s_total[FMT_SCALED_STRSIZE];
+
+ if (do_statvfs(conn, path, &st, 1) == -1)
+ return -1;
+ if (iflag) {
+ printf(" Inodes Used Avail "
+ "(root) %%Capacity\n");
+ printf("%11llu %11llu %11llu %11llu %3llu%%\n",
+ (unsigned long long)st.f_files,
+ (unsigned long long)(st.f_files - st.f_ffree),
+ (unsigned long long)st.f_favail,
+ (unsigned long long)st.f_ffree,
+ (unsigned long long)(100 * (st.f_files - st.f_ffree) /
+ st.f_files));
+ } else if (hflag) {
+ strlcpy(s_used, "error", sizeof(s_used));
+ strlcpy(s_avail, "error", sizeof(s_avail));
+ strlcpy(s_root, "error", sizeof(s_root));
+ strlcpy(s_total, "error", sizeof(s_total));
+ fmt_scaled((st.f_blocks - st.f_bfree) * st.f_frsize, s_used);
+ fmt_scaled(st.f_bavail * st.f_frsize, s_avail);
+ fmt_scaled(st.f_bfree * st.f_frsize, s_root);
+ fmt_scaled(st.f_blocks * st.f_frsize, s_total);
+ printf(" Size Used Avail (root) %%Capacity\n");
+ printf("%7sB %7sB %7sB %7sB %3llu%%\n",
+ s_total, s_used, s_avail, s_root,
+ (unsigned long long)(100 * (st.f_blocks - st.f_bfree) /
+ st.f_blocks));
+ } else {
+ printf(" Size Used Avail "
+ "(root) %%Capacity\n");
+ printf("%12llu %12llu %12llu %12llu %3llu%%\n",
+ (unsigned long long)(st.f_frsize * st.f_blocks / 1024),
+ (unsigned long long)(st.f_frsize *
+ (st.f_blocks - st.f_bfree) / 1024),
+ (unsigned long long)(st.f_frsize * st.f_bavail / 1024),
+ (unsigned long long)(st.f_frsize * st.f_bfree / 1024),
+ (unsigned long long)(100 * (st.f_blocks - st.f_bfree) /
+ st.f_blocks));
+ }
+ return 0;
+}
+
/*
* Undo escaping of glob sequences in place. Used to undo extra escaping
* applied in makeargv() when the string is destined for a function that
@@ -972,7 +1055,7 @@ makeargv(const char *arg, int *argcp)
}
static int
-parse_args(const char **cpp, int *pflag, int *lflag, int *iflag,
+parse_args(const char **cpp, int *pflag, int *lflag, int *iflag, int *hflag,
unsigned long *n_arg, char **path1, char **path2)
{
const char *cmd, *cp = *cpp;
@@ -1016,7 +1099,7 @@ parse_args(const char **cpp, int *pflag, int *lflag, int *iflag,
}
/* Get arguments and parse flags */
- *lflag = *pflag = *n_arg = 0;
+ *lflag = *pflag = *hflag = *n_arg = 0;
*path1 = *path2 = NULL;
optidx = 1;
switch (cmdnum) {
@@ -1068,6 +1151,18 @@ parse_args(const char **cpp, int *pflag, int *lflag, int *iflag,
if (cmdnum != I_RM)
undo_glob_escape(*path1);
break;
+ case I_DF:
+ if ((optidx = parse_df_flags(cmd, argv, argc, hflag,
+ iflag)) == -1)
+ return -1;
+ /* Default to current directory if no path specified */
+ if (argc - optidx < 1)
+ *path1 = NULL;
+ else {
+ *path1 = xstrdup(argv[optidx]);
+ undo_glob_escape(*path1);
+ }
+ break;
case I_LS:
if ((optidx = parse_ls_flags(argv, argc, lflag)) == -1)
return(-1);
@@ -1130,7 +1225,7 @@ parse_dispatch_command(struct sftp_conn *conn, const char *cmd, char **pwd,
int err_abort)
{
char *path1, *path2, *tmp;
- int pflag, lflag, iflag, cmdnum, i;
+ int pflag, lflag, iflag, hflag, cmdnum, i;
unsigned long n_arg;
Attrib a, *aa;
char path_buf[MAXPATHLEN];
@@ -1138,7 +1233,7 @@ parse_dispatch_command(struct sftp_conn *conn, const char *cmd, char **pwd,
glob_t g;
path1 = path2 = NULL;
- cmdnum = parse_args(&cmd, &pflag, &lflag, &iflag, &n_arg,
+ cmdnum = parse_args(&cmd, &pflag, &lflag, &iflag, &hflag, &n_arg,
&path1, &path2);
if (iflag != 0)
@@ -1232,6 +1327,13 @@ parse_dispatch_command(struct sftp_conn *conn, const char *cmd, char **pwd,
path1 = make_absolute(path1, *pwd);
err = do_globbed_ls(conn, path1, tmp, lflag);
break;
+ case I_DF:
+ /* Default to current directory if no path specified */
+ if (path1 == NULL)
+ path1 = xstrdup(*pwd);
+ path1 = make_absolute(path1, *pwd);
+ err = do_df(conn, path1, hflag, iflag);
+ break;
case I_LCHDIR:
if (chdir(path1) == -1) {
error("Couldn't change local directory to "
diff --git a/sftp.h b/sftp.h
index 0835da6e..b101b95a 100644
--- a/sftp.h
+++ b/sftp.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: sftp.h,v 1.7 2008/02/08 23:24:07 djm Exp $ */
+/* $OpenBSD: sftp.h,v 1.8 2008/04/18 12:32:11 djm Exp $ */
/*
* Copyright (c) 2001 Markus Friedl. All rights reserved.
@@ -79,6 +79,10 @@
#define SSH2_FXF_TRUNC 0x00000010
#define SSH2_FXF_EXCL 0x00000020
+/* statvfs@openssh.com f_flag flags */
+#define SSH2_FXE_STATVFS_ST_RDONLY 0x00000001
+#define SSH2_FXE_STATVFS_ST_NOSUID 0x00000002
+
/* status messages */
#define SSH2_FX_OK 0
#define SSH2_FX_EOF 1