diff options
Diffstat (limited to 'internal')
| -rw-r--r-- | internal/fusefrontend/args.go | 4 | ||||
| -rw-r--r-- | internal/fusefrontend_reverse/node.go | 13 | ||||
| -rw-r--r-- | internal/fusefrontend_reverse/node_dir_ops.go | 23 | ||||
| -rw-r--r-- | internal/fusefrontend_reverse/node_helpers.go | 5 | ||||
| -rw-r--r-- | internal/fusefrontend_reverse/root_node.go | 14 | 
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) | 
