diff options
Diffstat (limited to 'internal/fusefrontend_reverse')
-rw-r--r-- | internal/fusefrontend_reverse/excluder.go | 3 | ||||
-rw-r--r-- | internal/fusefrontend_reverse/excluder_test.go | 5 | ||||
-rw-r--r-- | internal/fusefrontend_reverse/node.go | 4 | ||||
-rw-r--r-- | internal/fusefrontend_reverse/node_helpers.go | 6 | ||||
-rw-r--r-- | internal/fusefrontend_reverse/root_node.go | 27 | ||||
-rw-r--r-- | internal/fusefrontend_reverse/virtualconf.go | 9 | ||||
-rw-r--r-- | internal/fusefrontend_reverse/virtualnode.go | 13 |
7 files changed, 50 insertions, 17 deletions
diff --git a/internal/fusefrontend_reverse/excluder.go b/internal/fusefrontend_reverse/excluder.go index 0faadfa..1cb4b80 100644 --- a/internal/fusefrontend_reverse/excluder.go +++ b/internal/fusefrontend_reverse/excluder.go @@ -1,7 +1,6 @@ package fusefrontend_reverse import ( - "io/ioutil" "log" "os" "strings" @@ -50,7 +49,7 @@ func getExclusionPatterns(args fusefrontend.Args) []string { // getLines reads a file and splits it into lines func getLines(file string) ([]string, error) { - buffer, err := ioutil.ReadFile(file) + buffer, err := os.ReadFile(file) if err != nil { return nil, err } diff --git a/internal/fusefrontend_reverse/excluder_test.go b/internal/fusefrontend_reverse/excluder_test.go index bb041ce..b44ddce 100644 --- a/internal/fusefrontend_reverse/excluder_test.go +++ b/internal/fusefrontend_reverse/excluder_test.go @@ -1,7 +1,6 @@ package fusefrontend_reverse import ( - "io/ioutil" "os" "reflect" "testing" @@ -23,7 +22,7 @@ func TestShouldPrefixExcludeValuesWithSlash(t *testing.T) { } func TestShouldReadExcludePatternsFromFiles(t *testing.T) { - tmpfile1, err := ioutil.TempFile("", "excludetest") + tmpfile1, err := os.CreateTemp("", "excludetest") if err != nil { t.Fatal(err) } @@ -31,7 +30,7 @@ func TestShouldReadExcludePatternsFromFiles(t *testing.T) { defer os.Remove(exclude1) defer tmpfile1.Close() - tmpfile2, err := ioutil.TempFile("", "excludetest") + tmpfile2, err := os.CreateTemp("", "excludetest") if err != nil { t.Fatal(err) } diff --git a/internal/fusefrontend_reverse/node.go b/internal/fusefrontend_reverse/node.go index 22ad975..30654e0 100644 --- a/internal/fusefrontend_reverse/node.go +++ b/internal/fusefrontend_reverse/node.go @@ -69,6 +69,10 @@ func (n *Node) Lookup(ctx context.Context, cName string, out *fuse.EntryOut) (ch n.translateSize(d.dirfd, cName, d.pName, &out.Attr) } + if rn.args.ForceOwner != nil { + out.Owner = *rn.args.ForceOwner + } + // Usually we always create a new Node ID by always incrementing the generation // number. // diff --git a/internal/fusefrontend_reverse/node_helpers.go b/internal/fusefrontend_reverse/node_helpers.go index 6bba097..3165db6 100644 --- a/internal/fusefrontend_reverse/node_helpers.go +++ b/internal/fusefrontend_reverse/node_helpers.go @@ -24,7 +24,6 @@ const ( // * base64(192 bytes) = 256 bytes (over 255!) // But the PKCS#7 padding is at least one byte. This means we can only use // 175 bytes for the file name. - shortNameMax = 175 ) // translateSize translates the ciphertext size in `out` into plaintext size. @@ -175,7 +174,7 @@ func (n *Node) lookupDiriv(ctx context.Context, out *fuse.EntryOut) (ch *fs.Inod errno = fs.ToErrno(err) return } - content := pathiv.Derive(d.cPath, pathiv.PurposeDirIV) + content := rn.deriveDirIV(d.cPath) var vf *VirtualMemNode vf, errno = n.newVirtualMemNode(content, st, inoTagDirIV) if errno != 0 { @@ -201,6 +200,9 @@ func (n *Node) lookupConf(ctx context.Context, out *fuse.EntryOut) (ch *fs.Inode // Get unique inode number rn.inoMap.TranslateStat(&st) out.Attr.FromStat(&st) + if rn.args.ForceOwner != nil { + out.Owner = *rn.args.ForceOwner + } // Create child node id := rn.uniqueStableAttr(uint32(st.Mode), st.Ino) node := &VirtualConfNode{path: p} diff --git a/internal/fusefrontend_reverse/root_node.go b/internal/fusefrontend_reverse/root_node.go index 1a68ffd..9c2de28 100644 --- a/internal/fusefrontend_reverse/root_node.go +++ b/internal/fusefrontend_reverse/root_node.go @@ -8,22 +8,20 @@ import ( "sync/atomic" "syscall" - "github.com/rfjakob/gocryptfs/v2/internal/exitcodes" - - "github.com/rfjakob/gocryptfs/v2/internal/tlog" - "golang.org/x/sys/unix" "github.com/hanwen/go-fuse/v2/fs" "github.com/hanwen/go-fuse/v2/fuse" "github.com/rfjakob/gocryptfs/v2/internal/contentenc" + "github.com/rfjakob/gocryptfs/v2/internal/exitcodes" "github.com/rfjakob/gocryptfs/v2/internal/fusefrontend" "github.com/rfjakob/gocryptfs/v2/internal/inomap" "github.com/rfjakob/gocryptfs/v2/internal/nametransform" "github.com/rfjakob/gocryptfs/v2/internal/syscallcompat" + "github.com/rfjakob/gocryptfs/v2/internal/tlog" - "github.com/sabhiram/go-gitignore" + ignore "github.com/sabhiram/go-gitignore" ) // RootNode is the root directory in a `gocryptfs -reverse` mount @@ -52,7 +50,9 @@ type RootNode struct { // makes go-fuse hand out separate FUSE Node IDs for each, and prevents // bizarre problems when inode numbers are reused behind our back, // like this one: https://github.com/rfjakob/gocryptfs/issues/802 - gen uint64 + gen atomic.Uint64 + // rootIno is the inode number that we report for the root node on mount + rootIno uint64 } // NewRootNode returns an encrypted FUSE overlay filesystem. @@ -61,9 +61,10 @@ type RootNode struct { func NewRootNode(args fusefrontend.Args, c *contentenc.ContentEnc, n *nametransform.NameTransform) *RootNode { var rootDev uint64 var st syscall.Stat_t + var statErr error var shortNameMax int - if err := syscall.Stat(args.Cipherdir, &st); err != nil { - tlog.Warn.Printf("Could not stat backing directory %q: %v", args.Cipherdir, err) + if statErr = syscall.Stat(args.Cipherdir, &st); statErr != nil { + tlog.Warn.Printf("Could not stat backing directory %q: %v", args.Cipherdir, statErr) if args.OneFileSystem { tlog.Fatal.Printf("This is a fatal error in combination with -one-file-system") os.Exit(exitcodes.CipherDir) @@ -83,6 +84,10 @@ func NewRootNode(args fusefrontend.Args, c *contentenc.ContentEnc, n *nametransf rootDev: rootDev, shortNameMax: shortNameMax, } + if statErr == nil { + rn.inoMap.TranslateStat(&st) + rn.rootIno = st.Ino + } if len(args.Exclude) > 0 || len(args.ExcludeWildcard) > 0 || len(args.ExcludeFrom) > 0 { rn.excluder = prepareExcluder(args) } @@ -170,6 +175,10 @@ func (rn *RootNode) uniqueStableAttr(mode uint32, ino uint64) fs.StableAttr { Ino: ino, // Make each directory entry a unique node by using a unique generation // value. Also see the comment at RootNode.gen for details. - Gen: atomic.AddUint64(&rn.gen, 1), + Gen: rn.gen.Add(1), } } + +func (rn *RootNode) RootIno() uint64 { + return rn.rootIno +} diff --git a/internal/fusefrontend_reverse/virtualconf.go b/internal/fusefrontend_reverse/virtualconf.go index 3643fad..ea358dd 100644 --- a/internal/fusefrontend_reverse/virtualconf.go +++ b/internal/fusefrontend_reverse/virtualconf.go @@ -18,6 +18,11 @@ type VirtualConfNode struct { path string } +// rootNode returns the Root Node of the filesystem. +func (n *VirtualConfNode) rootNode() *RootNode { + return n.Root().Operations().(*RootNode) +} + func (n *VirtualConfNode) Open(ctx context.Context, flags uint32) (fh fs.FileHandle, fuseFlags uint32, errno syscall.Errno) { fd, err := syscall.Open(n.path, syscall.O_RDONLY, 0) if err != nil { @@ -35,6 +40,10 @@ func (n *VirtualConfNode) Getattr(ctx context.Context, fh fs.FileHandle, out *fu return fs.ToErrno(err) } out.FromStat(&st) + rn := n.rootNode() + if rn.args.ForceOwner != nil { + out.Owner = *rn.args.ForceOwner + } return 0 } diff --git a/internal/fusefrontend_reverse/virtualnode.go b/internal/fusefrontend_reverse/virtualnode.go index 922cfa7..95e71ab 100644 --- a/internal/fusefrontend_reverse/virtualnode.go +++ b/internal/fusefrontend_reverse/virtualnode.go @@ -100,7 +100,18 @@ func (n *Node) newVirtualMemNode(content []byte, parentStat *syscall.Stat_t, ino st.Nlink = 1 var a fuse.Attr a.FromStat(st) - + // With inode number reuse and hard links, we could have returned + // wrong data for gocryptfs.diriv and gocryptfs.xyz.longname files, respectively + // (https://github.com/rfjakob/gocryptfs/issues/802). + // + // Now that this is fixed, ensure that rsync and similar tools pick up the new + // correct files by advancing mtime and ctime by 10 seconds, which should be more + // than any filesytems' timestamp granularity (FAT32 has 2 seconds). + a.Mtime += 10 + a.Ctime += 10 + if rn.args.ForceOwner != nil { + a.Owner = *rn.args.ForceOwner + } vf = &VirtualMemNode{content: content, attr: a} return } |