From 52a6f4f71ed464eb64dc05e0768d4af58bd2c195 Mon Sep 17 00:00:00 2001 From: Jakob Unterwurzacher Date: Sat, 24 Sep 2016 22:40:00 +0200 Subject: reverse: add longnameParentCache findLongnameParent has to read the whole directory to find the right file; add a simple cache to avoid most directory scans. --- internal/fusefrontend_reverse/reverse_longnames.go | 51 +++++++++++++++++++--- 1 file changed, 45 insertions(+), 6 deletions(-) (limited to 'internal/fusefrontend_reverse/reverse_longnames.go') 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) { -- cgit v1.2.3