diff options
| author | Jakob Unterwurzacher | 2018-10-14 21:55:37 +0200 | 
|---|---|---|
| committer | Jakob Unterwurzacher | 2019-01-01 16:24:09 +0100 | 
| commit | 0c1ceed1fa55e2a9174050c324f679821a5fca8d (patch) | |
| tree | 284819706e7bf81ad0d140c61e1788d3fcb2303c /internal | |
| parent | 932efbd4593fe6be6c86f0dafeaea32910b7c246 (diff) | |
fusefrontend: make GetAttr() symlink-safe
Use openBackingDir() and Fstatat().
High performance impact, though part of it should be
mitigated by adding DirIV caching to the new code paths.
$ ./benchmark.bash
Testing gocryptfs at /tmp/benchmark.bash.Eou: gocryptfs v1.6-37-ge3914b3-dirty; go-fuse v20170619-66-g6df8ddc; 2018-10-14 go1.11
WRITE: 262144000 bytes (262 MB, 250 MiB) copied, 1.2289 s, 213 MB/s
READ:  262144000 bytes (262 MB, 250 MiB) copied, 1.02616 s, 255 MB/s
UNTAR: 24.490
MD5:   13.120
LS:    3.368
RM:    9.232
Diffstat (limited to 'internal')
| -rw-r--r-- | internal/fusefrontend/fs.go | 26 | 
1 files changed, 16 insertions, 10 deletions
| diff --git a/internal/fusefrontend/fs.go b/internal/fusefrontend/fs.go index 8e443b7..a301231 100644 --- a/internal/fusefrontend/fs.go +++ b/internal/fusefrontend/fs.go @@ -73,30 +73,36 @@ func NewFS(args Args, c *contentenc.ContentEnc, n *nametransform.NameTransform)  }  // GetAttr implements pathfs.Filesystem. -func (fs *FS) GetAttr(name string, context *fuse.Context) (*fuse.Attr, fuse.Status) { -	tlog.Debug.Printf("FS.GetAttr('%s')", name) -	if fs.isFiltered(name) { +// +// GetAttr is symlink-safe through use of openBackingDir() and Fstatat(). +func (fs *FS) GetAttr(relPath string, context *fuse.Context) (*fuse.Attr, fuse.Status) { +	tlog.Debug.Printf("FS.GetAttr(%q)", relPath) +	if fs.isFiltered(relPath) {  		return nil, fuse.EPERM  	} -	cName, err := fs.encryptPath(name) +	dirfd, cName, err := fs.openBackingDir(relPath)  	if err != nil {  		return nil, fuse.ToStatus(err)  	} -	a, status := fs.FileSystem.GetAttr(cName, context) -	if a == nil { -		tlog.Debug.Printf("FS.GetAttr failed: %s", status.String()) -		return a, status +	var st unix.Stat_t +	err = syscallcompat.Fstatat(dirfd, cName, &st, unix.AT_SYMLINK_NOFOLLOW) +	syscall.Close(dirfd) +	if err != nil { +		return nil, fuse.ToStatus(err)  	} +	a := &fuse.Attr{} +	st2 := syscallcompat.Unix2syscall(st) +	a.FromStat(&st2)  	if a.IsRegular() {  		a.Size = fs.contentEnc.CipherSizeToPlainSize(a.Size)  	} else if a.IsSymlink() { -		target, _ := fs.Readlink(name, context) +		target, _ := fs.Readlink(relPath, context)  		a.Size = uint64(len(target))  	}  	if fs.args.ForceOwner != nil {  		a.Owner = *fs.args.ForceOwner  	} -	return a, status +	return a, fuse.OK  }  // mangleOpenFlags is used by Create() and Open() to convert the open flags the user | 
