aboutsummaryrefslogtreecommitdiff
path: root/internal/fusefrontend_reverse/rfile.go
diff options
context:
space:
mode:
authorJakob Unterwurzacher2017-05-25 21:33:16 +0200
committerJakob Unterwurzacher2017-05-25 21:33:16 +0200
commit9ecf2d1a3f69e3d995012073afe3fc664bd928f2 (patch)
tree7fb5ae498a58cfbafc04a0f856b15f5a41c3ba1c /internal/fusefrontend_reverse/rfile.go
parentbfc8d47747f8dee2528b2e505e69fbb106edaddc (diff)
fusefrontend_reverse: store derived values for hard-linked files
With hard links, the path to a file is not unique. This means that the ciphertext data depends on the path that is used to access the files. Fix that by storing the derived values when we encounter a hard-linked file. This means that the first path wins.
Diffstat (limited to 'internal/fusefrontend_reverse/rfile.go')
-rw-r--r--internal/fusefrontend_reverse/rfile.go46
1 files changed, 43 insertions, 3 deletions
diff --git a/internal/fusefrontend_reverse/rfile.go b/internal/fusefrontend_reverse/rfile.go
index 71d35a1..9a680bb 100644
--- a/internal/fusefrontend_reverse/rfile.go
+++ b/internal/fusefrontend_reverse/rfile.go
@@ -5,6 +5,10 @@ import (
"encoding/binary"
"io"
"os"
+ "syscall"
+
+ // In newer Go versions, this has moved to just "sync/syncmap".
+ "golang.org/x/sync/syncmap"
"github.com/hanwen/go-fuse/fuse"
"github.com/hanwen/go-fuse/fuse/nodefs"
@@ -26,6 +30,13 @@ type reverseFile struct {
contentEnc *contentenc.ContentEnc
}
+var inodeTable syncmap.Map
+
+type derivedIVContainer struct {
+ id []byte
+ block0IV []byte
+}
+
func (rfs *ReverseFS) newFile(relPath string, flags uint32) (nodefs.File, fuse.Status) {
absPath, err := rfs.abs(rfs.decryptPath(relPath))
if err != nil {
@@ -35,16 +46,45 @@ func (rfs *ReverseFS) newFile(relPath string, flags uint32) (nodefs.File, fuse.S
if err != nil {
return nil, fuse.ToStatus(err)
}
- id := derivePathIV(relPath, ivPurposeFileID)
+ var st syscall.Stat_t
+ err = syscall.Fstat(int(fd.Fd()), &st)
+ if err != nil {
+ tlog.Warn.Printf("newFile: Fstat error: %v", err)
+ return nil, fuse.ToStatus(err)
+ }
+ // See if we have that inode number already in the table
+ // (even if Nlink has dropped to 1)
+ var derivedIVs derivedIVContainer
+ v, found := inodeTable.Load(st.Ino)
+ if found {
+ tlog.Debug.Printf("ino%d: newFile: found in the inode table", st.Ino)
+ derivedIVs = v.(derivedIVContainer)
+ } else {
+ derivedIVs.id = derivePathIV(relPath, ivPurposeFileID)
+ derivedIVs.block0IV = derivePathIV(relPath, ivPurposeBlock0IV)
+ // Nlink > 1 means there is more than one path to this file.
+ // Store the derived values so we always return the same data,
+ // regardless of the path that is used to access the file.
+ // This means that the first path wins.
+ if st.Nlink > 1 {
+ v, found = inodeTable.LoadOrStore(st.Ino, derivedIVs)
+ if found {
+ // Another thread has stored a different value before we could.
+ derivedIVs = v.(derivedIVContainer)
+ } else {
+ tlog.Debug.Printf("ino%d: newFile: Nlink=%d, stored in the inode table", st.Ino, st.Nlink)
+ }
+ }
+ }
header := contentenc.FileHeader{
Version: contentenc.CurrentVersion,
- ID: id,
+ ID: derivedIVs.id,
}
return &reverseFile{
File: nodefs.NewDefaultFile(),
fd: fd,
header: header,
- block0IV: derivePathIV(relPath, ivPurposeBlock0IV),
+ block0IV: derivedIVs.block0IV,
contentEnc: rfs.contentEnc,
}, fuse.OK
}