diff options
| author | Jakob Unterwurzacher | 2017-08-09 21:44:15 +0200 | 
|---|---|---|
| committer | Jakob Unterwurzacher | 2017-08-09 22:00:53 +0200 | 
| commit | e80b5f2049edb794e340da629bce9e44485a4dbb (patch) | |
| tree | a5f2ef75478d3d67da5908743d6a7933a44ad4a1 /internal/nametransform/dirivcache | |
| parent | 75ec94a87a52a7230c9b7d9b3e150a0da2725e58 (diff) | |
nametransform: extend diriv cache to 100 entries
* extend the diriv cache to 100 entries
* add special handling for the immutable root diriv
The better cache allows to shed some complexity from the path
encryption logic (parent-of-parent check).
Mitigates https://github.com/rfjakob/gocryptfs/issues/127
Diffstat (limited to 'internal/nametransform/dirivcache')
| -rw-r--r-- | internal/nametransform/dirivcache/dirivcache.go | 77 | 
1 files changed, 51 insertions, 26 deletions
| diff --git a/internal/nametransform/dirivcache/dirivcache.go b/internal/nametransform/dirivcache/dirivcache.go index 890ebac..2708d89 100644 --- a/internal/nametransform/dirivcache/dirivcache.go +++ b/internal/nametransform/dirivcache/dirivcache.go @@ -5,59 +5,84 @@ import (  	"time"  ) -// Single-entry DirIV cache. Stores the directory IV and the encrypted -// path. +const ( +	maxEntries = 100 +	expireTime = 1 * time.Second +) + +type cacheEntry struct { +	// DirIV of the directory. +	iv []byte +	// Relative ciphertext path of the directory. +	cDir string +} + +// DirIVCache stores up to "maxEntries" directory IVs.  type DirIVCache struct { -	// Directory the DirIV belongs to -	dir string -	// Time the entry expires. +	// data in the cache, indexed by relative plaintext path +	// of the directory. +	data map[string]cacheEntry + +	// The DirIV of the root directory gets special treatment because it +	// cannot change (the root directory cannot be renamed or deleted). +	// It is unaffected by the expiry timer and cache clears. +	rootDirIV []byte + +	// expiry is the time when the whole cache expires.  	// The cached entry my become out-of-date if the ciphertext directory is  	// modifed behind the back of gocryptfs. Having an expiry time limits the  	// inconstency to one second, like attr_timeout does for the kernel  	// getattr cache.  	expiry time.Time -	// The DirIV -	iv []byte -	// Ecrypted version of "dir" -	cDir string - -	// Invalidated? -	cleared bool  	sync.RWMutex  } -// lookup - fetch entry for "dir" from the cache +// Lookup - fetch entry for "dir" from the cache  func (c *DirIVCache) Lookup(dir string) ([]byte, string) {  	c.RLock()  	defer c.RUnlock() -	if c.cleared || c.dir != dir { +	if dir == "" { +		return c.rootDirIV, "" +	} +	if c.data == nil {  		return nil, ""  	}  	if time.Since(c.expiry) > 0 { -		c.cleared = true +		c.data = nil  		return nil, ""  	} -	return c.iv, c.cDir +	v := c.data[dir] +	return v.iv, v.cDir  } -// store - write entry for "dir" into the cache +// Store - write entry for "dir" into the cache  func (c *DirIVCache) Store(dir string, iv []byte, cDir string) {  	c.Lock()  	defer c.Unlock() -	c.cleared = false -	c.iv = iv -	c.dir = dir -	c.cDir = cDir -	// Set expiry time one second into the future -	c.expiry = time.Now().Add(1 * time.Second) +	if dir == "" { +		c.rootDirIV = iv +	} +	if c.data == nil { +		c.data = make(map[string]cacheEntry, maxEntries) +		// Set expiry time one second into the future +		c.expiry = time.Now().Add(expireTime) +	} +	// Delete a random entry from the map if reached maxEntries +	if len(c.data) >= maxEntries { +		for k := range c.data { +			delete(c.data, k) +			break +		} +	} +	c.data[dir] = cacheEntry{iv, cDir}  }  // Clear ... clear the cache. -// Exported because it is called from fusefrontend when directories are -// renamed or deleted. +// Called from fusefrontend when directories are renamed or deleted.  func (c *DirIVCache) Clear() {  	c.Lock()  	defer c.Unlock() -	c.cleared = true +	// Will be re-initialized in the next Store() +	c.data = nil  } | 
