diff --git a/internal/fusefrontend/root_node.go b/internal/fusefrontend/root_node.go index 7d37520..7221be6 100644 --- a/internal/fusefrontend/root_node.go +++ b/internal/fusefrontend/root_node.go @@ -62,18 +62,28 @@ type RootNode struct { } func NewRootNode(args Args, c *contentenc.ContentEnc, n *nametransform.NameTransform) *RootNode { + var rootDev uint64 + var st syscall.Stat_t + if err := syscall.Stat(args.Cipherdir, &st); err != nil { + tlog.Warn.Printf("Could not stat backing directory %q: %v", args.Cipherdir, err) + } else { + rootDev = uint64(st.Dev) + } + if len(args.Exclude) > 0 { tlog.Warn.Printf("Forward mode does not support -exclude") } + ivLen := nametransform.DirIVLen if args.PlaintextNames { ivLen = 0 } + rn := &RootNode{ args: args, nameTransform: n, contentEnc: c, - inoMap: inomap.New(), + inoMap: inomap.New(rootDev), dirCache: dirCache{ivLen: ivLen}, quirks: syscallcompat.DetectQuirks(args.Cipherdir), } diff --git a/internal/fusefrontend_reverse/root_node.go b/internal/fusefrontend_reverse/root_node.go index d4c1e37..e15ddb0 100644 --- a/internal/fusefrontend_reverse/root_node.go +++ b/internal/fusefrontend_reverse/root_node.go @@ -2,10 +2,13 @@ package fusefrontend_reverse import ( "log" + "os" "path/filepath" "strings" "syscall" + "github.com/rfjakob/gocryptfs/v2/internal/exitcodes" + "github.com/rfjakob/gocryptfs/v2/internal/tlog" "golang.org/x/sys/unix" @@ -46,12 +49,14 @@ type RootNode struct { // ReverseFS provides an encrypted view. func NewRootNode(args fusefrontend.Args, c *contentenc.ContentEnc, n *nametransform.NameTransform) *RootNode { var rootDev uint64 - if args.OneFileSystem { - var st syscall.Stat_t - err := syscall.Stat(args.Cipherdir, &st) - if err != nil { - log.Panicf("Could not stat backing directory %q: %v", args.Cipherdir, err) + var st syscall.Stat_t + if err := syscall.Stat(args.Cipherdir, &st); err != nil { + tlog.Warn.Printf("Could not stat backing directory %q: %v", args.Cipherdir, err) + if args.OneFileSystem { + tlog.Fatal.Printf("This is a fatal error in combination with -one-file-system") + os.Exit(exitcodes.CipherDir) } + } else { rootDev = uint64(st.Dev) } @@ -59,7 +64,7 @@ func NewRootNode(args fusefrontend.Args, c *contentenc.ContentEnc, n *nametransf args: args, nameTransform: n, contentEnc: c, - inoMap: inomap.New(), + inoMap: inomap.New(rootDev), rootDev: rootDev, } if len(args.Exclude) > 0 || len(args.ExcludeWildcard) > 0 || len(args.ExcludeFrom) > 0 { diff --git a/internal/inomap/inomap.go b/internal/inomap/inomap.go index 97f9b61..997ea9b 100644 --- a/internal/inomap/inomap.go +++ b/internal/inomap/inomap.go @@ -49,13 +49,22 @@ type InoMap struct { } // New returns a new InoMap. -func New() *InoMap { - return &InoMap{ +// Inode numbers on device `rootDev` will be passed through as-is. +// If `rootDev` is zero, the first Translate() call decides the effective +// rootDev. +func New(rootDev uint64) *InoMap { + m := &InoMap{ namespaceMap: make(map[namespaceData]uint16), namespaceNext: 0, spillMap: make(map[QIno]uint64), spillNext: 0, } + if rootDev > 0 { + // Reserve namespace 0 for rootDev + m.namespaceMap[namespaceData{rootDev, 0}] = 0 + m.namespaceNext = 1 + } + return m } var spillWarn sync.Once diff --git a/internal/inomap/inomap_test.go b/internal/inomap/inomap_test.go index 6fbb4ef..9ec2932 100644 --- a/internal/inomap/inomap_test.go +++ b/internal/inomap/inomap_test.go @@ -6,7 +6,7 @@ import ( ) func TestTranslate(t *testing.T) { - m := New() + m := New(0) q := QIno{Ino: 1} out := m.Translate(q) if out != 1 { @@ -25,12 +25,7 @@ func TestTranslate(t *testing.T) { func TestTranslateStress(t *testing.T) { const baseDev = 12345 - m := New() - - // Make sure baseDev gets namespace id zero - var q QIno - q.Dev = baseDev - m.Translate(q) + m := New(baseDev) var wg sync.WaitGroup wg.Add(4) @@ -100,7 +95,7 @@ func TestTranslateStress(t *testing.T) { } func TestSpill(t *testing.T) { - m := New() + m := New(0) var q QIno q.Ino = maxPassthruIno + 1 out1 := m.Translate(q) @@ -119,7 +114,7 @@ func TestSpill(t *testing.T) { // TestUniqueness checks that unique (Dev, Flags, Ino) tuples get unique inode // numbers func TestUniqueness(t *testing.T) { - m := New() + m := New(0) var q QIno outMap := make(map[uint64]struct{}) for q.Dev = 0; q.Dev < 10; q.Dev++ { @@ -141,7 +136,7 @@ func TestUniqueness(t *testing.T) { } func BenchmarkTranslateSingleDev(b *testing.B) { - m := New() + m := New(0) var q QIno for n := 0; n < b.N; n++ { q.Ino = uint64(n % 1000) @@ -150,7 +145,7 @@ func BenchmarkTranslateSingleDev(b *testing.B) { } func BenchmarkTranslateManyDevs(b *testing.B) { - m := New() + m := New(0) var q QIno for n := 0; n < b.N; n++ { q.Dev = uint64(n % 10)