vfs,mount,cmount: use About to return the correct disk total/used/free

Disks total, used, free now shows correctly for mount and cmount (eg
`df` for Unix or in the Windows explorer).
This commit is contained in:
Nick Craig-Wood 2018-04-17 23:19:34 +01:00
parent ef3bcec76c
commit 2b855751fc
4 changed files with 106 additions and 5 deletions

View File

@ -275,6 +275,16 @@ func (fsys *FS) Statfs(path string, stat *fuse.Statfs_t) (errc int) {
stat.Bsize = blockSize // Block size
stat.Namemax = 255 // Maximum file name length?
stat.Frsize = blockSize // Fragment size, smallest addressable data size in the file system.
total, used, free := fsys.VFS.Statfs()
if total >= 0 {
stat.Blocks = uint64(total) / blockSize
}
if used >= 0 {
stat.Bfree = stat.Blocks - uint64(used)/blockSize
}
if free >= 0 {
stat.Bavail = uint64(free) / blockSize
}
return 0
}

View File

@ -62,6 +62,16 @@ func (f *FS) Statfs(ctx context.Context, req *fuse.StatfsRequest, resp *fuse.Sta
resp.Bsize = blockSize // Block size
resp.Namelen = 255 // Maximum file name length?
resp.Frsize = blockSize // Fragment size, smallest addressable data size in the file system.
total, used, free := f.VFS.Statfs()
if total >= 0 {
resp.Blocks = uint64(total) / blockSize
}
if used >= 0 {
resp.Bfree = resp.Blocks - uint64(used)/blockSize
}
if free >= 0 {
resp.Bavail = uint64(free) / blockSize
}
return nil
}

View File

@ -24,6 +24,7 @@ import (
"os"
"path"
"strings"
"sync"
"sync/atomic"
"time"
@ -165,11 +166,14 @@ var (
// VFS represents the top level filing system
type VFS struct {
f fs.Fs
root *Dir
Opt Options
cache *cache
cancel context.CancelFunc
f fs.Fs
root *Dir
Opt Options
cache *cache
cancel context.CancelFunc
usageMu sync.Mutex
usageTime time.Time
usage *fs.Usage
}
// Options is options for creating the vfs
@ -452,3 +456,40 @@ func (vfs *VFS) Rename(oldName, newName string) error {
}
return nil
}
// Statfs returns into about the filing system if known
//
// The values will be -1 if they aren't known
//
// This information is cached for the DirCacheTime interval
func (vfs *VFS) Statfs() (total, used, free int64) {
// defer log.Trace("/", "")("total=%d, used=%d, free=%d", &total, &used, &free)
vfs.usageMu.Lock()
defer vfs.usageMu.Unlock()
total, used, free = -1, -1, -1
doAbout := vfs.f.Features().About
if doAbout == nil {
return
}
if vfs.usageTime.IsZero() || time.Since(vfs.usageTime) >= vfs.Opt.DirCacheTime {
var err error
vfs.usage, err = doAbout()
vfs.usageTime = time.Now()
if err != nil {
fs.Errorf(vfs.f, "Statfs failed: %v", err)
return
}
}
if u := vfs.usage; u != nil {
if u.Total != nil {
total = *u.Total
}
if u.Free != nil {
free = *u.Free
}
if u.Used != nil {
used = *u.Used
}
}
return
}

View File

@ -251,3 +251,43 @@ func TestVFSRename(t *testing.T) {
err = vfs.Rename("file0", "not found/file0")
assert.Equal(t, os.ErrNotExist, err)
}
func TestVFSStatfs(t *testing.T) {
r := fstest.NewRun(t)
defer r.Finalise()
vfs := New(r.Fremote, nil)
// pre-conditions
assert.Nil(t, vfs.usage)
assert.True(t, vfs.usageTime.IsZero())
// read
total, used, free := vfs.Statfs()
require.NotNil(t, vfs.usage)
assert.False(t, vfs.usageTime.IsZero())
if vfs.usage.Total != nil {
assert.Equal(t, *vfs.usage.Total, total)
} else {
assert.Equal(t, -1, total)
}
if vfs.usage.Free != nil {
assert.Equal(t, *vfs.usage.Free, free)
} else {
assert.Equal(t, -1, free)
}
if vfs.usage.Used != nil {
assert.Equal(t, *vfs.usage.Used, used)
} else {
assert.Equal(t, -1, used)
}
// read cached
oldUsage := vfs.usage
oldTime := vfs.usageTime
total2, used2, free2 := vfs.Statfs()
assert.Equal(t, oldUsage, vfs.usage)
assert.Equal(t, total, total2)
assert.Equal(t, used, used2)
assert.Equal(t, free, free2)
assert.Equal(t, oldTime, vfs.usageTime)
}