aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog3
-rw-r--r--sshfs.c90
2 files changed, 91 insertions, 2 deletions
diff --git a/ChangeLog b/ChangeLog
index b66b416..a239210 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -9,6 +9,9 @@
* Limit write requests to 64kB.
+ * Support "statvfs@openssh.com" extension, which will be available
+ in OpenSSH 5.1.
+
2008-04-21 Miklos Szeredi <miklos@szeredi.hu>
* Fix incorrect disk usage reported by 'du' for files of size 4GB
diff --git a/sshfs.c b/sshfs.c
index d3d9ddc..39eec48 100644
--- a/sshfs.c
+++ b/sshfs.c
@@ -91,7 +91,12 @@
#define SSH_FXF_TRUNC 0x00000010
#define SSH_FXF_EXCL 0x00000020
+/* statvfs@openssh.com f_flag flags */
+#define SSH2_FXE_STATVFS_ST_RDONLY 0x00000001
+#define SSH2_FXE_STATVFS_ST_NOSUID 0x00000002
+
#define SFTP_EXT_POSIX_RENAME "posix-rename@openssh.com"
+#define SFTP_EXT_STATVFS "statvfs@openssh.com"
#define PROTO_VERSION 3
@@ -203,6 +208,7 @@ struct sshfs {
int password_stdin;
char *password;
int ext_posix_rename;
+ int ext_statvfs;
/* statistics */
uint64_t bytes_sent;
@@ -642,6 +648,48 @@ static int buf_get_attrs(struct buffer *buf, struct stat *stbuf, int *flagsp)
return 0;
}
+static int buf_get_statvfs(struct buffer *buf, struct statvfs *stbuf)
+{
+ uint32_t bsize;
+ uint32_t frsize;
+ uint64_t blocks;
+ uint64_t bfree;
+ uint64_t bavail;
+ uint64_t files;
+ uint64_t ffree;
+ uint64_t favail;
+ uint32_t fsid;
+ uint32_t flag;
+ uint32_t namemax;
+
+ if (buf_get_uint32(buf, &bsize) == -1 ||
+ buf_get_uint32(buf, &frsize) == -1 ||
+ buf_get_uint64(buf, &blocks) == -1 ||
+ buf_get_uint64(buf, &bfree) == -1 ||
+ buf_get_uint64(buf, &bavail) == -1 ||
+ buf_get_uint64(buf, &files) == -1 ||
+ buf_get_uint64(buf, &ffree) == -1 ||
+ buf_get_uint64(buf, &favail) == -1 ||
+ buf_get_uint32(buf, &fsid) == -1 ||
+ buf_get_uint32(buf, &flag) == -1 ||
+ buf_get_uint32(buf, &namemax) == -1) {
+ return -1;
+ }
+
+ memset(stbuf, 0, sizeof(struct statvfs));
+ stbuf->f_bsize = bsize;
+ stbuf->f_frsize = frsize;
+ stbuf->f_blocks = blocks;
+ stbuf->f_bfree = bfree;
+ stbuf->f_bavail = bavail;
+ stbuf->f_files = files;
+ stbuf->f_ffree = ffree;
+ stbuf->f_favail = favail;
+ stbuf->f_namemax = namemax;
+
+ return 0;
+}
+
static int buf_get_entries(struct buffer *buf, fuse_cache_dirh_t h,
fuse_cache_dirfil_t filler)
{
@@ -1294,6 +1342,8 @@ static int sftp_init_reply_ok(struct buffer *buf, uint32_t *version)
sshfs.ext_posix_rename = 1;
sshfs.rename_workaround = 0;
}
+ if (strcmp(ext, SFTP_EXT_STATVFS) == 0)
+ sshfs.ext_statvfs = 1;
} while (buf2.len < buf2.size);
}
return 0;
@@ -2464,10 +2514,31 @@ static int sshfs_write(const char *path, const char *wbuf, size_t size,
return err ? err : (int) size;
}
+static int sshfs_ext_statvfs(const char *path, struct statvfs *stbuf)
+{
+ int err;
+ struct buffer buf;
+ struct buffer outbuf;
+ buf_init(&buf, 0);
+ buf_add_string(&buf, SFTP_EXT_STATVFS);
+ buf_add_path(&buf, path);
+ err = sftp_request(SSH_FXP_EXTENDED, &buf, SSH_FXP_EXTENDED_REPLY,
+ &outbuf);
+ if (!err) {
+ if (buf_get_statvfs(&outbuf, stbuf) == -1)
+ err = -EIO;
+ buf_free(&outbuf);
+ }
+ buf_free(&buf);
+ return err;
+}
+
+
#if FUSE_VERSION >= 25
static int sshfs_statfs(const char *path, struct statvfs *buf)
{
- (void) path;
+ if (sshfs.ext_statvfs)
+ return sshfs_ext_statvfs(path, buf);
buf->f_namemax = 255;
buf->f_bsize = sshfs.blksize;
@@ -2484,7 +2555,22 @@ static int sshfs_statfs(const char *path, struct statvfs *buf)
#else
static int sshfs_statfs(const char *path, struct statfs *buf)
{
- (void) path;
+ if (sshfs.ext_statvfs) {
+ int err;
+ struct statvfs vbuf;
+
+ err = sshfs_ext_statvfs(path, &vbuf);
+ if (!err) {
+ buf->f_bsize = vbuf.f_bsize;
+ buf->f_blocks = vbuf.f_blocks;
+ buf->f_bfree = vbuf.f_bfree;
+ buf->f_bavail = vbuf.f_bavail;
+ buf->f_files = vbuf.f_files;
+ buf->f_ffree = vbuf.f_ffree;
+ buf->f_namelen = vbuf.f_namemax;
+ }
+ return err;
+ }
buf->f_namelen = 255;
buf->f_bsize = sshfs.blksize;