diff options
-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 |