danim7 fb1b8ced38 fusefrontend_reverse: consistent file owners for .diriv, .name files
This PR addresses the Issue #95, about "Confusing file owner for
longname files in reverse mode".

It affects only the reverse mode, and introduces two
modifications:

1) The "gocryptfs.longname.XXXX.name" files are assigned the owner and
group of the underlying plaintext file. Therefore it is consistent
with the file "gocryptfs.longname.XXXX" that has the encrypted
contents of the plaintext file.

2) The two virtual files mentioned above are given -r--r--r--
permissions. This is consistent with the behavior described in
function Access in internal/fusefrontend_reverse/rfs.go where all
virtual files are always readable. Behavior also observed in point
c) in #95 .

Issue #95 URL: https://github.com/rfjakob/gocryptfs/issues/95
Pull request URL: https://github.com/rfjakob/gocryptfs/pull/97
2017-03-28 22:58:03 +02:00

102 lines
2.5 KiB
Go

package fusefrontend_reverse
import (
"log"
"os"
"path/filepath"
"sync"
"syscall"
"time"
"github.com/hanwen/go-fuse/fuse"
"github.com/hanwen/go-fuse/fuse/nodefs"
"github.com/rfjakob/gocryptfs/internal/nametransform"
"github.com/rfjakob/gocryptfs/internal/tlog"
)
const (
shortNameMax = 176
)
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 initLongnameCache() {
if longnameParentCache != nil {
return
}
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 {
tlog.Warn.Printf("findLongnameParent: opendir failed: %v\n", err)
return "", err
}
dirEntries, err := dirfd.Readdirnames(-1)
if err != nil {
return "", err
}
longnameCacheLock.Lock()
defer longnameCacheLock.Unlock()
for _, plaintextName = range dirEntries {
if len(plaintextName) <= shortNameMax {
continue
}
cName := rfs.nameTransform.EncryptName(plaintextName, dirIV)
if len(cName) <= syscall.NAME_MAX {
log.Panic("logic error or wrong shortNameMax constant?")
}
hName := rfs.nameTransform.HashLongName(cName)
longnameParentCache[hName] = plaintextName
if longname == hName {
hit = plaintextName
}
}
if hit == "" {
return "", syscall.ENOENT
}
return hit, nil
}
func (rfs *ReverseFS) newNameFile(relPath string) (nodefs.File, fuse.Status) {
dotName := filepath.Base(relPath) // gocryptfs.longname.XYZ.name
longname := dotName[:len(dotName)-len(nametransform.LongNameSuffix)] // gocryptfs.longname.XYZ
cDir := saneDir(relPath)
pDir, err := rfs.decryptPath(cDir)
if err != nil {
return nil, fuse.ToStatus(err)
}
dirIV := derivePathIV(cDir, ivPurposeDirIV)
e, err := rfs.findLongnameParent(pDir, dirIV, longname)
if err != nil {
return nil, fuse.ToStatus(err)
}
content := []byte(rfs.nameTransform.EncryptName(e, dirIV))
parentFile := filepath.Join(rfs.args.Cipherdir, pDir, e)
return rfs.newVirtualFile(content, parentFile)
}