summaryrefslogtreecommitdiff
path: root/internal/fusefrontend_reverse
diff options
context:
space:
mode:
Diffstat (limited to 'internal/fusefrontend_reverse')
-rw-r--r--internal/fusefrontend_reverse/node_dir_ops.go81
-rw-r--r--internal/fusefrontend_reverse/node_helpers.go6
-rw-r--r--internal/fusefrontend_reverse/virtualfile.go15
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
+)