summaryrefslogtreecommitdiff
path: root/internal
diff options
context:
space:
mode:
Diffstat (limited to 'internal')
-rw-r--r--internal/fusefrontend/args.go4
-rw-r--r--internal/fusefrontend_reverse/node.go13
-rw-r--r--internal/fusefrontend_reverse/node_dir_ops.go23
-rw-r--r--internal/fusefrontend_reverse/node_helpers.go5
-rw-r--r--internal/fusefrontend_reverse/root_node.go14
5 files changed, 50 insertions, 9 deletions
diff --git a/internal/fusefrontend/args.go b/internal/fusefrontend/args.go
index ae1c30c..d92c3ff 100644
--- a/internal/fusefrontend/args.go
+++ b/internal/fusefrontend/args.go
@@ -49,4 +49,8 @@ type Args struct {
// SharedStorage disables caching & hard link tracking,
// enabled via cli flag "-sharedstorage"
SharedStorage bool
+ // OneFileSystem disables crossing filesystem boundaries,
+ // like rsync's `--one-file-system` does.
+ // Only applicable to reverse mode.
+ OneFileSystem bool
}
diff --git a/internal/fusefrontend_reverse/node.go b/internal/fusefrontend_reverse/node.go
index 787b99b..1b2fd67 100644
--- a/internal/fusefrontend_reverse/node.go
+++ b/internal/fusefrontend_reverse/node.go
@@ -22,6 +22,10 @@ import (
// in a `gocryptfs -reverse` mount.
type Node struct {
fs.Inode
+ // isOtherFilesystem is used for --one-filesystem.
+ // It is set when the device number of this file or directory
+ // is different from n.rootNode().rootDev.
+ isOtherFilesystem bool
}
// Lookup - FUSE call for discovering a file.
@@ -31,7 +35,14 @@ func (n *Node) Lookup(ctx context.Context, cName string, out *fuse.EntryOut) (ch
if t == typeDiriv {
// gocryptfs.diriv
return n.lookupDiriv(ctx, out)
- } else if t == typeName {
+ }
+ rn := n.rootNode()
+ if rn.args.OneFileSystem && n.isOtherFilesystem {
+ // With --one-file-system, we present mountpoints as empty. That is,
+ // it contains only a gocryptfs.diriv file (allowed above).
+ return nil, syscall.ENOENT
+ }
+ if t == typeName {
// gocryptfs.longname.*.name
return n.lookupLongnameName(ctx, cName, out)
} else if t == typeConfig {
diff --git a/internal/fusefrontend_reverse/node_dir_ops.go b/internal/fusefrontend_reverse/node_dir_ops.go
index c287284..21b9775 100644
--- a/internal/fusefrontend_reverse/node_dir_ops.go
+++ b/internal/fusefrontend_reverse/node_dir_ops.go
@@ -23,6 +23,22 @@ import (
// This function is symlink-safe through use of openBackingDir() and
// ReadDirIVAt().
func (n *Node) Readdir(ctx context.Context) (stream fs.DirStream, errno syscall.Errno) {
+ // Virtual files: at least one gocryptfs.diriv file
+ virtualFiles := []fuse.DirEntry{
+ {Mode: virtualFileMode, Name: nametransform.DirIVFilename},
+ }
+ rn := n.rootNode()
+
+ // This directory is a mountpoint. Present it as empty.
+ if rn.args.OneFileSystem && n.isOtherFilesystem {
+ if rn.args.PlaintextNames {
+ return fs.NewListDirStream(nil), 0
+ } else {
+ // An "empty" directory still has a gocryptfs.diriv file!
+ return fs.NewListDirStream(virtualFiles), 0
+ }
+ }
+
d, errno := n.prepareAtSyscall("")
if errno != 0 {
return
@@ -41,8 +57,6 @@ func (n *Node) Readdir(ctx context.Context) (stream fs.DirStream, errno syscall.
return nil, fs.ToErrno(err)
}
- rn := n.rootNode()
-
// Filter out excluded entries
entries = rn.excludeDirEntries(d, entries)
@@ -50,11 +64,6 @@ func (n *Node) Readdir(ctx context.Context) (stream fs.DirStream, errno syscall.
return n.readdirPlaintextnames(entries)
}
- // Virtual files: at least one gocryptfs.diriv file
- virtualFiles := []fuse.DirEntry{
- {Mode: virtualFileMode, Name: nametransform.DirIVFilename},
- }
-
dirIV := pathiv.Derive(d.cPath, pathiv.PurposeDirIV)
// Encrypt names
for i := range entries {
diff --git a/internal/fusefrontend_reverse/node_helpers.go b/internal/fusefrontend_reverse/node_helpers.go
index 92f6a87..7b286a0 100644
--- a/internal/fusefrontend_reverse/node_helpers.go
+++ b/internal/fusefrontend_reverse/node_helpers.go
@@ -91,6 +91,7 @@ func (n *Node) prepareAtSyscall(child string) (d *dirfdPlus, errno syscall.Errno
// newChild attaches a new child inode to n.
// The passed-in `st` will be modified to get a unique inode number.
func (n *Node) newChild(ctx context.Context, st *syscall.Stat_t, out *fuse.EntryOut) *fs.Inode {
+ isOtherFilesystem := (uint64(st.Dev) != n.rootNode().rootDev)
// Get unique inode number
rn := n.rootNode()
rn.inoMap.TranslateStat(st)
@@ -101,7 +102,9 @@ func (n *Node) newChild(ctx context.Context, st *syscall.Stat_t, out *fuse.Entry
Gen: 1,
Ino: st.Ino,
}
- node := &Node{}
+ node := &Node{
+ isOtherFilesystem: isOtherFilesystem,
+ }
return n.NewInode(ctx, node, id)
}
diff --git a/internal/fusefrontend_reverse/root_node.go b/internal/fusefrontend_reverse/root_node.go
index b072f85..d57e1e6 100644
--- a/internal/fusefrontend_reverse/root_node.go
+++ b/internal/fusefrontend_reverse/root_node.go
@@ -36,17 +36,31 @@ type RootNode struct {
// inoMap translates inode numbers from different devices to unique inode
// numbers.
inoMap *inomap.InoMap
+ // rootDev stores the device number of the backing directory. Used for
+ // --one-file-system.
+ rootDev uint64
}
// NewRootNode returns an encrypted FUSE overlay filesystem.
// In this case (reverse mode) the backing directory is plain-text and
// 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)
+ }
+ rootDev = uint64(st.Dev)
+ }
+
rn := &RootNode{
args: args,
nameTransform: n,
contentEnc: c,
inoMap: inomap.New(),
+ rootDev: rootDev,
}
if len(args.Exclude) > 0 || len(args.ExcludeWildcard) > 0 || len(args.ExcludeFrom) > 0 {
rn.excluder = prepareExcluder(args)