v2api/reverse: implement Readdir

This commit is contained in:
Jakob Unterwurzacher 2020-08-01 22:28:25 +02:00
parent f54d21c384
commit 6c26cda531
3 changed files with 102 additions and 0 deletions

View File

@ -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
}

View File

@ -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
}

View File

@ -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
)