aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--internal/fusefrontend_reverse/reverse_longnames.go51
-rw-r--r--internal/fusefrontend_reverse/rfs.go15
2 files changed, 56 insertions, 10 deletions
diff --git a/internal/fusefrontend_reverse/reverse_longnames.go b/internal/fusefrontend_reverse/reverse_longnames.go
index 46e1791..487802f 100644
--- a/internal/fusefrontend_reverse/reverse_longnames.go
+++ b/internal/fusefrontend_reverse/reverse_longnames.go
@@ -3,7 +3,9 @@ package fusefrontend_reverse
import (
"os"
"path/filepath"
+ "sync"
"syscall"
+ "time"
"github.com/hanwen/go-fuse/fuse"
"github.com/hanwen/go-fuse/fuse/nodefs"
@@ -15,7 +17,37 @@ const (
shortNameMax = 176
)
-func (rfs *reverseFS) findLongnameParent(dir string, dirIV []byte, longname string) (string, error) {
+type dirIVNameStruct struct {
+ dirIV [nametransform.DirIVLen]byte
+ name string
+}
+
+var longnameParentCache map[string]string
+var longnameCacheLock sync.Mutex
+
+// Very simple cache cleaner: Nuke it every hour
+func longnameCacheCleaner() {
+ for {
+ time.Sleep(time.Hour)
+ longnameCacheLock.Lock()
+ longnameParentCache = map[string]string{}
+ longnameCacheLock.Unlock()
+ }
+}
+
+func init() {
+ longnameParentCache = map[string]string{}
+ go longnameCacheCleaner()
+}
+
+// findLongnameParent converts "gocryptfs.longname.XYZ" to the plaintext name
+func (rfs *reverseFS) findLongnameParent(dir string, dirIV []byte, longname string) (plaintextName string, err error) {
+ longnameCacheLock.Lock()
+ hit := longnameParentCache[longname]
+ longnameCacheLock.Unlock()
+ if hit != "" {
+ return hit, nil
+ }
absDir := filepath.Join(rfs.args.Cipherdir, dir)
dirfd, err := os.Open(absDir)
if err != nil {
@@ -25,20 +57,27 @@ func (rfs *reverseFS) findLongnameParent(dir string, dirIV []byte, longname stri
if err != nil {
return "", err
}
- for _, e := range dirEntries {
- if len(e) <= shortNameMax {
+ longnameCacheLock.Lock()
+ defer longnameCacheLock.Unlock()
+ for _, plaintextName = range dirEntries {
+ if len(plaintextName) <= shortNameMax {
continue
}
- cName := rfs.nameTransform.EncryptName(e, dirIV)
+ cName := rfs.nameTransform.EncryptName(plaintextName, dirIV)
if len(cName) <= syscall.NAME_MAX {
panic("logic error or wrong shortNameMax constant?")
}
hName := nametransform.HashLongName(cName)
+ longnameParentCache[hName] = plaintextName
if longname == hName {
- return e, nil
+ hit = plaintextName
}
}
- return "", syscall.ENOENT
+ if hit == "" {
+ return "", syscall.ENOENT
+ } else {
+ return hit, nil
+ }
}
func (rfs *reverseFS) newNameFile(relPath string) (nodefs.File, fuse.Status) {
diff --git a/internal/fusefrontend_reverse/rfs.go b/internal/fusefrontend_reverse/rfs.go
index 7305687..9ebf91c 100644
--- a/internal/fusefrontend_reverse/rfs.go
+++ b/internal/fusefrontend_reverse/rfs.go
@@ -248,9 +248,15 @@ func (rfs *reverseFS) OpenDir(cipherPath string, context *fuse.Context) ([]fuse.
if entries == nil {
return nil, status
}
+ // Allocate maximum possible number of virtual files.
+ // If all files have long names we need a virtual ".name" file for each,
+ // plus one for gocryptfs.diriv.
+ virtualFiles := make([]fuse.DirEntry, len(entries)+1)
// Virtual gocryptfs.diriv file
- dirIVEntry := fuse.DirEntry{syscall.S_IFREG | 0400, nametransform.DirIVFilename}
- virtualFiles := []fuse.DirEntry{dirIVEntry}
+ virtualFiles[0] = fuse.DirEntry{syscall.S_IFREG | 0400, nametransform.DirIVFilename}
+ // Actually used entries
+ nVirtual := 1
+
// Encrypt names
dirIV := deriveDirIV(cipherPath)
for i := range entries {
@@ -263,12 +269,13 @@ func (rfs *reverseFS) OpenDir(cipherPath string, context *fuse.Context) ([]fuse.
if len(cName) > syscall.NAME_MAX {
cName = nametransform.HashLongName(cName)
dotNameFile := fuse.DirEntry{syscall.S_IFREG | 0600, cName + nametransform.LongNameSuffix}
- virtualFiles = append(virtualFiles, dotNameFile)
+ virtualFiles[nVirtual] = dotNameFile
+ nVirtual++
}
}
entries[i].Name = cName
}
- entries = append(entries, virtualFiles...)
+ entries = append(entries, virtualFiles[:nVirtual]...)
return entries, fuse.OK
}