master
go 53 lines 2.17 KB
Raw
1 // FUSE stat helpers. go-fuse only builds on linux, darwin, and freebsd.
2 //go:build (linux || darwin || freebsd) && !nofuse
3
4 package mount
5
6 import (
7 "strconv"
8 "strings"
9
10 "github.com/hanwen/go-fuse/v2/fuse"
11 )
12
13 // StatBlockSize is the POSIX stat(2) block unit. The st_blocks field
14 // reports allocation in 512-byte units regardless of the filesystem's
15 // real block size (see `man 2 stat`). Tools like `du`, `ls -s`, and
16 // `find -size` multiply st_blocks by this constant to compute bytes.
17 const StatBlockSize = 512
18
19 // DefaultBlksize is the preferred I/O size (stat.st_blksize) FUSE mounts
20 // advertise when no chunker-derived value applies (readonly /ipfs, or
21 // writable /mfs with a rabin/buzhash chunker). Larger hints let tools
22 // like cp, dd, and rsync use bigger buffers, amortizing FUSE syscall and
23 // DAG-walk overhead. 1 MiB matches the chunk size of Kubo's
24 // cross-implementation CID-deterministic import profile (IPIP-499).
25 // Hardcoded instead of tracking boxo's chunker default so the stat(2)
26 // contract stays stable across Kubo and boxo upgrades.
27 const DefaultBlksize = 1024 * 1024
28
29 // SizeToStatBlocks converts a byte size to the number of 512-byte blocks
30 // reported by POSIX stat(2) in the st_blocks field, rounded up so a
31 // non-empty file reports at least one block.
32 func SizeToStatBlocks(size uint64) uint64 {
33 return (size + StatBlockSize - 1) / StatBlockSize
34 }
35
36 // BlksizeFromChunker derives the preferred I/O size hint for the writable
37 // mounts from the user's Import.UnixFSChunker setting. It extracts the
38 // byte count from `size-<bytes>` and returns DefaultBlksize for rabin,
39 // buzhash, or malformed values (where there is no single preferred size).
40 // Values are clamped to fuse.MAX_KERNEL_WRITE because the kernel splits
41 // any larger userspace read/write into MAX_KERNEL_WRITE-sized FUSE ops
42 // regardless, so hinting past the ceiling just wastes userspace buffers.
43 func BlksizeFromChunker(chunkerStr string) uint32 {
44 if sizeStr, ok := strings.CutPrefix(chunkerStr, "size-"); ok {
45 if size, err := strconv.ParseUint(sizeStr, 10, 64); err == nil && size > 0 {
46 if size > fuse.MAX_KERNEL_WRITE {
47 return fuse.MAX_KERNEL_WRITE
48 }
49 return uint32(size)
50 }
51 }
52 return DefaultBlksize
53 }