reverse: add longnameParentCache

findLongnameParent has to read the whole directory to find the
right file; add a simple cache to avoid most directory scans.
This commit is contained in:
Jakob Unterwurzacher 2016-09-24 22:40:00 +02:00
parent 6ffd07f02a
commit 52a6f4f71e
2 changed files with 56 additions and 10 deletions

View File

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

View File

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