diff --git a/cmd/serve/sftp/handler.go b/cmd/serve/sftp/handler.go index 559580064..04adaf432 100644 --- a/cmd/serve/sftp/handler.go +++ b/cmd/serve/sftp/handler.go @@ -116,6 +116,26 @@ func (v vfsHandler) Filecmd(r *sftp.Request) error { return nil } +// StatVFS implements the statvfs@openssh.com extension, returning filesystem +// usage information from the VFS. It satisfies sftp.StatVFSFileCmder. +func (v vfsHandler) StatVFS(r *sftp.Request) (*sftp.StatVFS, error) { + const blockSize = 4096 + total, _, free := v.Statfs() + blocks := uint64(total) / blockSize + bfree := uint64(free) / blockSize + return &sftp.StatVFS{ + Bsize: blockSize, + Frsize: blockSize, + Blocks: blocks, + Bfree: bfree, + Bavail: bfree, + Files: 1e9, // total file inodes - made up as the VFS has no concept of these + Ffree: 1e9, // free file inodes + Favail: 1e9, // free file inodes for non-root + Namemax: 255, // maximum filename length + }, nil +} + type listerat []os.FileInfo // Modeled after strings.Reader's ReadAt() implementation diff --git a/cmd/serve/sftp/handler_test.go b/cmd/serve/sftp/handler_test.go index b41d09cc9..f85af9543 100644 --- a/cmd/serve/sftp/handler_test.go +++ b/cmd/serve/sftp/handler_test.go @@ -168,6 +168,21 @@ func TestSetstatTruncate(t *testing.T) { assert.Equal(t, strings.Repeat("A", 10), string(got)) } +// Test that the statvfs@openssh.com extension returns filesystem usage from +// the VFS rather than an unsupported status. +func TestStatVFS(t *testing.T) { + vfsOpt := vfscommon.Opt + vfsOpt.CacheMode = vfscommon.CacheModeWrites + client := startTestServer(t, &vfsOpt) + + st, err := client.StatVFS("/") + require.NoError(t, err) + + assert.Greater(t, st.TotalSpace(), uint64(0), "expected non-zero total space") + assert.LessOrEqual(t, st.FreeSpace(), st.TotalSpace(), "free space should not exceed total") + assert.Equal(t, uint64(255), st.Namemax) +} + // writeFile writes contents to fileName via the client truncating any existing // data, the way a normal upload does. func writeFile(client *sftp.Client, fileName, contents string) error { diff --git a/cmd/serve/sftp/sftp_test.go b/cmd/serve/sftp/sftp_test.go index e18d6b86d..ecbe500cb 100644 --- a/cmd/serve/sftp/sftp_test.go +++ b/cmd/serve/sftp/sftp_test.go @@ -33,10 +33,11 @@ const ( // check interfaces var ( - _ sftp.FileReader = vfsHandler{} - _ sftp.FileWriter = vfsHandler{} - _ sftp.FileCmder = vfsHandler{} - _ sftp.FileLister = vfsHandler{} + _ sftp.FileReader = vfsHandler{} + _ sftp.FileWriter = vfsHandler{} + _ sftp.FileCmder = vfsHandler{} + _ sftp.FileLister = vfsHandler{} + _ sftp.StatVFSFileCmder = vfsHandler{} ) // TestSftp runs the sftp server then runs the unit tests for the