diff options
Diffstat (limited to 'internal/fusefrontend')
| -rw-r--r-- | internal/fusefrontend/dircache.go | 22 | ||||
| -rw-r--r-- | internal/fusefrontend/node_helpers.go | 32 | ||||
| -rw-r--r-- | internal/fusefrontend/root_node.go | 2 | 
3 files changed, 43 insertions, 13 deletions
| diff --git a/internal/fusefrontend/dircache.go b/internal/fusefrontend/dircache.go index d6ec52c..f8932d8 100644 --- a/internal/fusefrontend/dircache.go +++ b/internal/fusefrontend/dircache.go @@ -21,13 +21,11 @@ const (  	enableDebugMessages = false  	// Enable hit rate statistics printing  	enableStats = false - -	pathFmt = "%-40q"  )  type dirCacheEntryStruct struct { -	// relative plaintext path to the directory -	dirRelPath string +	// pointer to the Node this entry belongs to +	node *Node  	// fd to the directory (opened with O_PATH!)  	fd int  	// content of gocryptfs.diriv in this directory @@ -46,7 +44,7 @@ func (e *dirCacheEntryStruct) Clear() {  		}  	}  	e.fd = -1 -	e.dirRelPath = "" +	e.node = nil  	e.iv = nil  } @@ -76,7 +74,7 @@ func (d *dirCacheStruct) Clear() {  // Store the entry in the cache. The passed "fd" will be Dup()ed, and the caller  // can close their copy at will. -func (d *dirCacheStruct) Store(dirRelPath string, fd int, iv []byte) { +func (d *dirCacheStruct) Store(node *Node, fd int, iv []byte) {  	// Note: package ensurefds012, imported from main, guarantees that dirCache  	// can never get fds 0,1,2.  	if fd <= 0 || len(iv) != nametransform.DirIVLen { @@ -94,9 +92,9 @@ func (d *dirCacheStruct) Store(dirRelPath string, fd int, iv []byte) {  		tlog.Warn.Printf("dirCache.Store: Dup failed: %v", err)  		return  	} -	d.dbg("Store  "+pathFmt+" fd=%d iv=%x\n", dirRelPath, fd2, iv) +	d.dbg("dirCache.Store  %p fd=%d iv=%x\n", node, fd2, iv)  	e.fd = fd2 -	e.dirRelPath = dirRelPath +	e.node = node  	e.iv = iv  	// expireThread is started on the first Lookup()  	if !d.expireThreadRunning { @@ -108,7 +106,7 @@ func (d *dirCacheStruct) Store(dirRelPath string, fd int, iv []byte) {  // Lookup checks if relPath is in the cache, and returns an (fd, iv) pair.  // It returns (-1, nil) if not found. The fd is internally Dup()ed and the  // caller must close it when done. -func (d *dirCacheStruct) Lookup(dirRelPath string) (fd int, iv []byte) { +func (d *dirCacheStruct) Lookup(node *Node) (fd int, iv []byte) {  	d.Lock()  	defer d.Unlock()  	if enableStats { @@ -121,7 +119,7 @@ func (d *dirCacheStruct) Lookup(dirRelPath string) (fd int, iv []byte) {  			// Cache slot is empty  			continue  		} -		if dirRelPath != e.dirRelPath { +		if node != e.node {  			// Not the right path  			continue  		} @@ -135,7 +133,7 @@ func (d *dirCacheStruct) Lookup(dirRelPath string) (fd int, iv []byte) {  		break  	}  	if fd == 0 { -		d.dbg("Lookup "+pathFmt+" miss\n", dirRelPath) +		d.dbg("dirCache.Lookup %p miss\n", node)  		return -1, nil  	}  	if enableStats { @@ -144,7 +142,7 @@ func (d *dirCacheStruct) Lookup(dirRelPath string) (fd int, iv []byte) {  	if fd <= 0 || len(iv) != nametransform.DirIVLen {  		log.Panicf("Lookup sanity check failed: fd=%d len=%d", fd, len(iv))  	} -	d.dbg("Lookup "+pathFmt+" hit fd=%d dup=%d iv=%x\n", dirRelPath, e.fd, fd, iv) +	d.dbg("dirCache.Lookup %p hit fd=%d dup=%d iv=%x\n", node, e.fd, fd, iv)  	return fd, iv  } diff --git a/internal/fusefrontend/node_helpers.go b/internal/fusefrontend/node_helpers.go index a8d1ebe..c44a559 100644 --- a/internal/fusefrontend/node_helpers.go +++ b/internal/fusefrontend/node_helpers.go @@ -9,6 +9,7 @@ import (  	"github.com/hanwen/go-fuse/v2/fuse" +	"github.com/rfjakob/gocryptfs/internal/nametransform"  	"github.com/rfjakob/gocryptfs/internal/syscallcompat"  	"github.com/rfjakob/gocryptfs/internal/tlog"  ) @@ -83,11 +84,28 @@ func (n *Node) rootNode() *RootNode {  // a child of this node.  // If `child` is empty, the (dirfd, cName) pair refers to this node itself.  func (n *Node) prepareAtSyscall(child string) (dirfd int, cName string, errno syscall.Errno) { +	rn := n.rootNode() + +	// Cache lookup +	// TODO: also handle caching for root node & plaintextnames +	cacheable := (child != "" && !rn.args.PlaintextNames) +	if cacheable { +		var iv []byte +		dirfd, iv = rn.dirCache.Lookup(n) +		if dirfd > 0 { +			cName, err := rn.nameTransform.EncryptAndHashName(child, iv) +			if err != nil { +				return -1, "", fs.ToErrno(err) +			} +			return dirfd, cName, 0 +		} +	} + +	// Slowpath  	p := n.Path()  	if child != "" {  		p = filepath.Join(p, child)  	} -	rn := n.rootNode()  	if rn.isFiltered(p) {  		errno = syscall.EPERM  		return @@ -96,6 +114,18 @@ func (n *Node) prepareAtSyscall(child string) (dirfd int, cName string, errno sy  	if err != nil {  		errno = fs.ToErrno(err)  	} + +	// Cache store +	// TODO: also handle caching for root node & plaintextnames +	if cacheable { +		// TODO: openBackingDir already calls ReadDirIVAt(). Get the data out. +		iv, err := nametransform.ReadDirIVAt(dirfd) +		if err != nil { +			syscall.Close(dirfd) +			return -1, "", fs.ToErrno(err) +		} +		rn.dirCache.Store(n, dirfd, iv) +	}  	return  } diff --git a/internal/fusefrontend/root_node.go b/internal/fusefrontend/root_node.go index bdefafa..cdac4d4 100644 --- a/internal/fusefrontend/root_node.go +++ b/internal/fusefrontend/root_node.go @@ -48,6 +48,8 @@ type RootNode struct {  	// When -idle was used when mounting, idleMonitor() sets it to 1  	// periodically.  	IsIdle uint32 +	// dirCache caches directory fds +	dirCache dirCacheStruct  	// inoMap translates inode numbers from different devices to unique inode  	// numbers.  	inoMap inomap.TranslateStater | 
