mount,cmount: clip the number of blocks to 2^32-1 on macOS

OSX FUSE only supports 32 bit number of blocks which means that block
counts have been wrapping.  This causes f_bavail to be 0 which in turn
causes problems with programs like borg backup.

Fixes #2356
This commit is contained in:
Nick Craig-Wood 2018-06-26 09:26:34 +01:00
parent 4eefd05dcf
commit 174ca22936
3 changed files with 28 additions and 5 deletions

View File

@ -8,11 +8,11 @@ import (
"io" "io"
"os" "os"
"path" "path"
"runtime"
"sync" "sync"
"time" "time"
"github.com/billziss-gh/cgofuse/fuse" "github.com/billziss-gh/cgofuse/fuse"
"github.com/ncw/rclone/cmd/mountlib"
"github.com/ncw/rclone/fs" "github.com/ncw/rclone/fs"
"github.com/ncw/rclone/fs/log" "github.com/ncw/rclone/fs/log"
"github.com/ncw/rclone/vfs" "github.com/ncw/rclone/vfs"
@ -263,10 +263,7 @@ 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
fsBlocks := uint64(1 << 50) const fsBlocks = (1 << 50) / blockSize
if runtime.GOOS == "windows" {
fsBlocks = (1 << 43) - 1
}
stat.Blocks = fsBlocks // Total data blocks in file system. stat.Blocks = fsBlocks // Total data blocks in file system.
stat.Bfree = fsBlocks // Free blocks in file system. stat.Bfree = fsBlocks // Free blocks in file system.
stat.Bavail = fsBlocks // Free blocks in file system if you're not root. stat.Bavail = fsBlocks // Free blocks in file system if you're not root.
@ -285,6 +282,9 @@ func (fsys *FS) Statfs(path string, stat *fuse.Statfs_t) (errc int) {
if free >= 0 { if free >= 0 {
stat.Bavail = uint64(free) / blockSize stat.Bavail = uint64(free) / blockSize
} }
mountlib.ClipBlocks(&stat.Blocks)
mountlib.ClipBlocks(&stat.Bfree)
mountlib.ClipBlocks(&stat.Bavail)
return 0 return 0
} }

View File

@ -9,6 +9,7 @@ import (
"bazil.org/fuse" "bazil.org/fuse"
fusefs "bazil.org/fuse/fs" fusefs "bazil.org/fuse/fs"
"github.com/ncw/rclone/cmd/mountlib"
"github.com/ncw/rclone/fs" "github.com/ncw/rclone/fs"
"github.com/ncw/rclone/fs/log" "github.com/ncw/rclone/fs/log"
"github.com/ncw/rclone/vfs" "github.com/ncw/rclone/vfs"
@ -72,6 +73,9 @@ func (f *FS) Statfs(ctx context.Context, req *fuse.StatfsRequest, resp *fuse.Sta
if free >= 0 { if free >= 0 {
resp.Bavail = uint64(free) / blockSize resp.Bavail = uint64(free) / blockSize
} }
mountlib.ClipBlocks(&resp.Blocks)
mountlib.ClipBlocks(&resp.Bfree)
mountlib.ClipBlocks(&resp.Bavail)
return nil return nil
} }

View File

@ -293,3 +293,22 @@ be copied to the vfs cache before opening with --vfs-cache-mode full.
return commandDefintion return commandDefintion
} }
// ClipBlocks clips the blocks pointed to to the OS max
func ClipBlocks(b *uint64) {
var max uint64
switch runtime.GOOS {
case "windows":
max = (1 << 43) - 1
case "darwin":
// OSX FUSE only supports 32 bit number of blocks
// https://github.com/osxfuse/osxfuse/issues/396
max = (1 << 32) - 1
default:
// no clipping
return
}
if *b > max {
*b = max
}
}