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