diff options
| -rw-r--r-- | internal/fusefrontend_reverse/node_dir_ops.go | 81 | ||||
| -rw-r--r-- | internal/fusefrontend_reverse/node_helpers.go | 6 | ||||
| -rw-r--r-- | internal/fusefrontend_reverse/virtualfile.go | 15 | 
3 files changed, 102 insertions, 0 deletions
| diff --git a/internal/fusefrontend_reverse/node_dir_ops.go b/internal/fusefrontend_reverse/node_dir_ops.go new file mode 100644 index 0000000..c48d884 --- /dev/null +++ b/internal/fusefrontend_reverse/node_dir_ops.go @@ -0,0 +1,81 @@ +package fusefrontend_reverse + +import ( +	"context" +	"syscall" + +	"golang.org/x/sys/unix" + +	"github.com/hanwen/go-fuse/v2/fs" +	"github.com/hanwen/go-fuse/v2/fuse" + +	"github.com/rfjakob/gocryptfs/internal/configfile" +	"github.com/rfjakob/gocryptfs/internal/nametransform" +	"github.com/rfjakob/gocryptfs/internal/pathiv" +	"github.com/rfjakob/gocryptfs/internal/syscallcompat" +) + +// Readdir - FUSE call. +// +// This function is symlink-safe through use of openBackingDir() and +// ReadDirIVAt(). +func (n *Node) Readdir(ctx context.Context) (stream fs.DirStream, errno syscall.Errno) { +	dirfd, cName, errno := n.prepareAtSyscall("") +	if errno != 0 { +		return +	} +	defer syscall.Close(dirfd) + +	// Read plaintext directory +	var entries []fuse.DirEntry +	fd, err := syscallcompat.Openat(dirfd, cName, syscall.O_RDONLY|syscall.O_DIRECTORY|syscall.O_NOFOLLOW, 0) +	if err != nil { +		return nil, fs.ToErrno(err) +	} +	defer syscall.Close(fd) +	entries, err = syscallcompat.Getdents(fd) +	if err != nil { +		return nil, fs.ToErrno(err) +	} + +	rn := n.rootNode() +	if rn.args.PlaintextNames { +		panic("todo") +	} + +	// Filter out excluded entries +	//TODO +	//entries = rfs.excludeDirEntries(relPath, entries) + +	// Virtual files: at least one gocryptfs.diriv file +	virtualFiles := []fuse.DirEntry{ +		{Mode: virtualFileMode, Name: nametransform.DirIVFilename}, +	} + +	cipherPath := n.Path() +	dirIV := pathiv.Derive(cipherPath, pathiv.PurposeDirIV) +	// Encrypt names +	for i := range entries { +		var cName string +		// ".gocryptfs.reverse.conf" in the root directory is mapped to "gocryptfs.conf" +		if n.isRoot() && entries[i].Name == configfile.ConfReverseName && +			!rn.args.ConfigCustom { +			cName = configfile.ConfDefaultName +		} else { +			cName = rn.nameTransform.EncryptName(entries[i].Name, dirIV) +			if len(cName) > unix.NAME_MAX { +				cName = rn.nameTransform.HashLongName(cName) +				dotNameFile := fuse.DirEntry{ +					Mode: virtualFileMode, +					Name: cName + nametransform.LongNameSuffix, +				} +				virtualFiles = append(virtualFiles, dotNameFile) +			} +		} +		entries[i].Name = cName +	} + +	// Add virtual files +	entries = append(entries, virtualFiles...) +	return fs.NewListDirStream(entries), 0 +} diff --git a/internal/fusefrontend_reverse/node_helpers.go b/internal/fusefrontend_reverse/node_helpers.go index a26ee81..24cdbd1 100644 --- a/internal/fusefrontend_reverse/node_helpers.go +++ b/internal/fusefrontend_reverse/node_helpers.go @@ -65,3 +65,9 @@ func (n *Node) newChild(ctx context.Context, st *syscall.Stat_t, out *fuse.Entry  	node := &Node{}  	return n.NewInode(ctx, node, id)  } + +// isRoot returns true if this node is the root node +func (n *Node) isRoot() bool { +	rn := n.rootNode() +	return &rn.Node == n +} diff --git a/internal/fusefrontend_reverse/virtualfile.go b/internal/fusefrontend_reverse/virtualfile.go new file mode 100644 index 0000000..a92c127 --- /dev/null +++ b/internal/fusefrontend_reverse/virtualfile.go @@ -0,0 +1,15 @@ +package fusefrontend_reverse + +import ( +	"syscall" +) + +const ( +	// virtualFileMode is the mode to use for virtual files (gocryptfs.diriv and +	// *.name). They are always readable, as stated in func Access +	virtualFileMode = syscall.S_IFREG | 0444 +	// We use inomap's `Tag` feature to generate unique inode numbers for +	// virtual files. These are the tags we use. +	inoTagDirIV    = 1 +	inoTagNameFile = 2 +) | 
