mirror of
https://github.com/rclone/rclone
synced 2024-12-21 11:45:56 +01:00
vfs,mount,cmount: report 1PB free for unknown disk sizes
Factor the logic into the VFS layer so we don't have to duplicate it into mount and cmount. See: https://forum.rclone.org/t/rclone-mount-question/15454/
This commit is contained in:
parent
9f3449d944
commit
da41db4712
@ -268,25 +268,15 @@ func (fsys *FS) Releasedir(path string, fh uint64) (errc int) {
|
|||||||
func (fsys *FS) Statfs(path string, stat *fuse.Statfs_t) (errc int) {
|
func (fsys *FS) Statfs(path string, stat *fuse.Statfs_t) (errc int) {
|
||||||
defer log.Trace(path, "")("stat=%+v, errc=%d", stat, &errc)
|
defer log.Trace(path, "")("stat=%+v, errc=%d", stat, &errc)
|
||||||
const blockSize = 4096
|
const blockSize = 4096
|
||||||
const fsBlocks = (1 << 50) / blockSize
|
total, _, free := fsys.VFS.Statfs()
|
||||||
stat.Blocks = fsBlocks // Total data blocks in file system.
|
stat.Blocks = uint64(total) / blockSize // Total data blocks in file system.
|
||||||
stat.Bfree = fsBlocks // Free blocks in file system.
|
stat.Bfree = uint64(free) / blockSize // Free blocks in file system.
|
||||||
stat.Bavail = fsBlocks // Free blocks in file system if you're not root.
|
stat.Bavail = stat.Bfree // Free blocks in file system if you're not root.
|
||||||
stat.Files = 1e9 // Total files in file system.
|
stat.Files = 1e9 // Total files in file system.
|
||||||
stat.Ffree = 1e9 // Free files in file system.
|
stat.Ffree = 1e9 // Free files in file system.
|
||||||
stat.Bsize = blockSize // Block size
|
stat.Bsize = blockSize // Block size
|
||||||
stat.Namemax = 255 // Maximum file name length?
|
stat.Namemax = 255 // Maximum file name length?
|
||||||
stat.Frsize = blockSize // Fragment size, smallest addressable data size in the file system.
|
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
|
|
||||||
}
|
|
||||||
mountlib.ClipBlocks(&stat.Blocks)
|
mountlib.ClipBlocks(&stat.Blocks)
|
||||||
mountlib.ClipBlocks(&stat.Bfree)
|
mountlib.ClipBlocks(&stat.Bfree)
|
||||||
mountlib.ClipBlocks(&stat.Bavail)
|
mountlib.ClipBlocks(&stat.Bavail)
|
||||||
|
@ -54,25 +54,15 @@ var _ fusefs.FSStatfser = (*FS)(nil)
|
|||||||
func (f *FS) Statfs(ctx context.Context, req *fuse.StatfsRequest, resp *fuse.StatfsResponse) (err error) {
|
func (f *FS) Statfs(ctx context.Context, req *fuse.StatfsRequest, resp *fuse.StatfsResponse) (err error) {
|
||||||
defer log.Trace("", "")("stat=%+v, err=%v", resp, &err)
|
defer log.Trace("", "")("stat=%+v, err=%v", resp, &err)
|
||||||
const blockSize = 4096
|
const blockSize = 4096
|
||||||
const fsBlocks = (1 << 50) / blockSize
|
total, _, free := f.VFS.Statfs()
|
||||||
resp.Blocks = fsBlocks // Total data blocks in file system.
|
resp.Blocks = uint64(total) / blockSize // Total data blocks in file system.
|
||||||
resp.Bfree = fsBlocks // Free blocks in file system.
|
resp.Bfree = uint64(free) / blockSize // Free blocks in file system.
|
||||||
resp.Bavail = fsBlocks // Free blocks in file system if you're not root.
|
resp.Bavail = resp.Bfree // Free blocks in file system if you're not root.
|
||||||
resp.Files = 1e9 // Total files in file system.
|
resp.Files = 1e9 // Total files in file system.
|
||||||
resp.Ffree = 1e9 // Free files in file system.
|
resp.Ffree = 1e9 // Free files in file system.
|
||||||
resp.Bsize = blockSize // Block size
|
resp.Bsize = blockSize // Block size
|
||||||
resp.Namelen = 255 // Maximum file name length?
|
resp.Namelen = 255 // Maximum file name length?
|
||||||
resp.Frsize = blockSize // Fragment size, smallest addressable data size in the file system.
|
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
|
|
||||||
}
|
|
||||||
mountlib.ClipBlocks(&resp.Blocks)
|
mountlib.ClipBlocks(&resp.Blocks)
|
||||||
mountlib.ClipBlocks(&resp.Bfree)
|
mountlib.ClipBlocks(&resp.Bfree)
|
||||||
mountlib.ClipBlocks(&resp.Bavail)
|
mountlib.ClipBlocks(&resp.Bavail)
|
||||||
|
46
vfs/vfs.go
46
vfs/vfs.go
@ -477,6 +477,37 @@ func (vfs *VFS) Rename(oldName, newName string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This works out the missing values from (total, used, free) using
|
||||||
|
// unknownFree as the intended free space
|
||||||
|
func fillInMissingSizes(total, used, free, unknownFree int64) (newTotal, newUsed, newFree int64) {
|
||||||
|
if total < 0 {
|
||||||
|
if free >= 0 {
|
||||||
|
total = free
|
||||||
|
} else {
|
||||||
|
total = unknownFree
|
||||||
|
}
|
||||||
|
if used >= 0 {
|
||||||
|
total += used
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// total is now defined
|
||||||
|
if used < 0 {
|
||||||
|
if free >= 0 {
|
||||||
|
used = total - free
|
||||||
|
} else {
|
||||||
|
used = 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// used is now defined
|
||||||
|
if free < 0 {
|
||||||
|
free = total - used
|
||||||
|
}
|
||||||
|
return total, used, free
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the total size isn't known then we will aim for this many bytes free (1PB)
|
||||||
|
const unknownFreeBytes = 1 << 50
|
||||||
|
|
||||||
// Statfs returns into about the filing system if known
|
// Statfs returns into about the filing system if known
|
||||||
//
|
//
|
||||||
// The values will be -1 if they aren't known
|
// The values will be -1 if they aren't known
|
||||||
@ -488,10 +519,7 @@ func (vfs *VFS) Statfs() (total, used, free int64) {
|
|||||||
defer vfs.usageMu.Unlock()
|
defer vfs.usageMu.Unlock()
|
||||||
total, used, free = -1, -1, -1
|
total, used, free = -1, -1, -1
|
||||||
doAbout := vfs.f.Features().About
|
doAbout := vfs.f.Features().About
|
||||||
if doAbout == nil {
|
if doAbout != nil && (vfs.usageTime.IsZero() || time.Since(vfs.usageTime) >= vfs.Opt.DirCacheTime) {
|
||||||
return
|
|
||||||
}
|
|
||||||
if vfs.usageTime.IsZero() || time.Since(vfs.usageTime) >= vfs.Opt.DirCacheTime {
|
|
||||||
var err error
|
var err error
|
||||||
vfs.usage, err = doAbout(context.TODO())
|
vfs.usage, err = doAbout(context.TODO())
|
||||||
vfs.usageTime = time.Now()
|
vfs.usageTime = time.Now()
|
||||||
@ -510,15 +538,7 @@ func (vfs *VFS) Statfs() (total, used, free int64) {
|
|||||||
if u.Used != nil {
|
if u.Used != nil {
|
||||||
used = *u.Used
|
used = *u.Used
|
||||||
}
|
}
|
||||||
if total < 0 && free >= 0 && used >= 0 {
|
|
||||||
total = free + used
|
|
||||||
}
|
|
||||||
if free < 0 && total >= 0 && used >= 0 {
|
|
||||||
free = total - used
|
|
||||||
}
|
|
||||||
if used < 0 && total >= 0 && free >= 0 {
|
|
||||||
used = total - free
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
total, used, free = fillInMissingSizes(total, used, free, unknownFreeBytes)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,7 @@ package vfs
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
"testing"
|
"testing"
|
||||||
@ -311,3 +312,51 @@ func TestVFSStatfs(t *testing.T) {
|
|||||||
assert.Equal(t, free, free2)
|
assert.Equal(t, free, free2)
|
||||||
assert.Equal(t, oldTime, vfs.usageTime)
|
assert.Equal(t, oldTime, vfs.usageTime)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestFillInMissingSizes(t *testing.T) {
|
||||||
|
const unknownFree = 10
|
||||||
|
for _, test := range []struct {
|
||||||
|
total, free, used int64
|
||||||
|
wantTotal, wantUsed, wantFree int64
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
total: 20, free: 5, used: 15,
|
||||||
|
wantTotal: 20, wantFree: 5, wantUsed: 15,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
total: 20, free: 5, used: -1,
|
||||||
|
wantTotal: 20, wantFree: 5, wantUsed: 15,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
total: 20, free: -1, used: 15,
|
||||||
|
wantTotal: 20, wantFree: 5, wantUsed: 15,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
total: 20, free: -1, used: -1,
|
||||||
|
wantTotal: 20, wantFree: 20, wantUsed: 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
total: -1, free: 5, used: 15,
|
||||||
|
wantTotal: 20, wantFree: 5, wantUsed: 15,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
total: -1, free: 15, used: -1,
|
||||||
|
wantTotal: 15, wantFree: 15, wantUsed: 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
total: -1, free: -1, used: 15,
|
||||||
|
wantTotal: 25, wantFree: 10, wantUsed: 15,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
total: -1, free: -1, used: -1,
|
||||||
|
wantTotal: 10, wantFree: 10, wantUsed: 0,
|
||||||
|
},
|
||||||
|
} {
|
||||||
|
t.Run(fmt.Sprintf("total=%d,free=%d,used=%d", test.total, test.free, test.used), func(t *testing.T) {
|
||||||
|
gotTotal, gotUsed, gotFree := fillInMissingSizes(test.total, test.used, test.free, unknownFree)
|
||||||
|
assert.Equal(t, test.wantTotal, gotTotal, "total")
|
||||||
|
assert.Equal(t, test.wantUsed, gotUsed, "used")
|
||||||
|
assert.Equal(t, test.wantFree, gotFree, "free")
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user