aboutsummaryrefslogtreecommitdiff
path: root/internal/fusefrontend_reverse/rfile.go
diff options
context:
space:
mode:
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
}