summaryrefslogtreecommitdiff
path: root/internal/fusefrontend/fs.go
diff options
context:
space:
mode:
Diffstat (limited to 'internal/fusefrontend/fs.go')
-rw-r--r--internal/fusefrontend/fs.go14
1 files changed, 9 insertions, 5 deletions
diff --git a/internal/fusefrontend/fs.go b/internal/fusefrontend/fs.go
index a301231..022fd5c 100644
--- a/internal/fusefrontend/fs.go
+++ b/internal/fusefrontend/fs.go
@@ -377,6 +377,8 @@ func (fs *FS) StatFs(path string) *fuse.StatfsOut {
// decryptSymlinkTarget: "cData64" is base64-decoded and decrypted
// like file contents (GCM).
// The empty string decrypts to the empty string.
+//
+// This function does not do any I/O and is hence symlink-safe.
func (fs *FS) decryptSymlinkTarget(cData64 string) (string, error) {
if cData64 == "" {
return "", nil
@@ -392,14 +394,16 @@ func (fs *FS) decryptSymlinkTarget(cData64 string) (string, error) {
return string(data), nil
}
-// Readlink implements pathfs.Filesystem.
+// Readlink - FUSE call.
+//
+// Symlink-safe through openBackingDir() + Readlinkat().
func (fs *FS) Readlink(relPath string, context *fuse.Context) (out string, status fuse.Status) {
- cPath, err := fs.encryptPath(relPath)
+ dirfd, cName, err := fs.openBackingDir(relPath)
if err != nil {
return "", fuse.ToStatus(err)
}
- cAbsPath := filepath.Join(fs.args.Cipherdir, cPath)
- cTarget, err := os.Readlink(cAbsPath)
+ defer syscall.Close(dirfd)
+ cTarget, err := syscallcompat.Readlinkat(dirfd, cName)
if err != nil {
return "", fuse.ToStatus(err)
}
@@ -409,7 +413,7 @@ func (fs *FS) Readlink(relPath string, context *fuse.Context) (out string, statu
// Symlinks are encrypted like file contents (GCM) and base64-encoded
target, err := fs.decryptSymlinkTarget(cTarget)
if err != nil {
- tlog.Warn.Printf("Readlink %q: decrypting target failed: %v", cPath, err)
+ tlog.Warn.Printf("Readlink %q: decrypting target failed: %v", cName, err)
return "", fuse.EIO
}
return string(target), fuse.OK