From 1d0a442405e8fc7a0742a8f8db2ea0f874f750a5 Mon Sep 17 00:00:00 2001
From: Jakob Unterwurzacher
Date: Sun, 29 Nov 2015 19:57:48 +0100
Subject: OpenDir performance: Read DirIV once and reuse it for all names

Formerly, we called decryptPath for every name.
That resulted in a directory walk that reads in all diriv files
on the way.

Massive improvement for RM and LS (check performance.txt for details)

VERSION         UNTAR   RM   LS
v0.4               48    5    1.5
v0.5-rc1           56   19    7
v0.5-rc1-1         54    9    4.1   <---- THIS VERSION
---
 pathfs_frontend/fs.go | 58 ++++++++++++++++++++++++++++-----------------------
 1 file changed, 32 insertions(+), 26 deletions(-)

(limited to 'pathfs_frontend')

diff --git a/pathfs_frontend/fs.go b/pathfs_frontend/fs.go
index e68e6bc..fe9a8b0 100644
--- a/pathfs_frontend/fs.go
+++ b/pathfs_frontend/fs.go
@@ -75,35 +75,41 @@ func (fs *FS) OpenDir(dirName string, context *fuse.Context) ([]fuse.DirEntry, f
 	if err != nil {
 		return nil, fuse.ToStatus(err)
 	}
+	// Read ciphertext directory
 	cipherEntries, status := fs.FileSystem.OpenDir(cDirName, context)
+	if cipherEntries == nil {
+		return nil, status
+	}
+	// Get DirIV (stays zero if DirIV if off)
+	cachedIV := make([]byte, cryptfs.DIRIV_LEN)
+	if fs.args.DirIV {
+		// Read the DirIV once and use it for all later name decryptions
+		cDirAbsPath := filepath.Join(fs.args.Cipherdir, cDirName)
+		cachedIV, err = fs.CryptFS.ReadDirIV(cDirAbsPath)
+		if err != nil {
+			return nil, fuse.ToStatus(err)
+		}
+	}
+	// Decrypt filenames
 	var plain []fuse.DirEntry
-	if cipherEntries != nil {
-		for i := range cipherEntries {
-			cName := cipherEntries[i].Name
-			if dirName == "" && cName == cryptfs.ConfDefaultName {
-				// silently ignore "gocryptfs.conf" in the top level dir
-				continue
-			}
-			if fs.args.DirIV && cName == cryptfs.DIRIV_FILENAME {
-				// silently ignore "gocryptfs.diriv" everywhere if dirIV is enabled
-				continue
-			}
-			var name string
-			if !fs.args.DirIV {
-				name, err = fs.decryptPath(cName)
-			} else {
-				// When dirIV is enabled we need the full path to be able to decrypt it
-				cPath := filepath.Join(cDirName, cName)
-				name, err = fs.decryptPath(cPath)
-				name = filepath.Base(name)
-			}
-			if err != nil {
-				cryptfs.Warn.Printf("Invalid name \"%s\" in dir \"%s\": %s\n", cName, dirName, err)
-				continue
-			}
-			cipherEntries[i].Name = name
-			plain = append(plain, cipherEntries[i])
+	for i := range cipherEntries {
+		cName := cipherEntries[i].Name
+		if dirName == "" && cName == cryptfs.ConfDefaultName {
+			// silently ignore "gocryptfs.conf" in the top level dir
+			continue
+		}
+		if fs.args.DirIV && cName == cryptfs.DIRIV_FILENAME {
+			// silently ignore "gocryptfs.diriv" everywhere if dirIV is enabled
+			continue
+		}
+		var name string
+		name, err = fs.CryptFS.DecryptName(cName, cachedIV)
+		if err != nil {
+			cryptfs.Warn.Printf("Invalid name \"%s\" in dir \"%s\": %s\n", cName, dirName, err)
+			continue
 		}
+		cipherEntries[i].Name = name
+		plain = append(plain, cipherEntries[i])
 	}
 	return plain, status
 }
-- 
cgit v1.2.3