serve sftp: implement statvfs@openssh.com to report disk usage
The statvfs@openssh.com extension was advertised but returned an unsupported status, so clients couldn't query the amount of free and used space. Implement it using the VFS Statfs method, which reports the backend's usage where the backend supports About.
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user