@@ -5,6 +5,10 @@ import (
55"encoding/binary"
66"io"
77"os"
8+ "syscall"
9+
10+ // In newer Go versions, this has moved to just "sync/syncmap".
11+ "golang.org/x/sync/syncmap"
812
913"github.com/hanwen/go-fuse/fuse"
1014"github.com/hanwen/go-fuse/fuse/nodefs"
@@ -26,6 +30,13 @@ type reverseFile struct {
2630contentEnc * contentenc.ContentEnc
2731}
2832
33+ var inodeTable syncmap.Map
34+
35+ type derivedIVContainer struct {
36+ id []byte
37+ block0IV []byte
38+ }
39+
2940func (rfs * ReverseFS )newFile (relPath string ,flags uint32 ) (nodefs.File , fuse.Status ) {
3041absPath ,err := rfs .abs (rfs .decryptPath (relPath ))
3142if err != nil {
@@ -35,16 +46,45 @@ func (rfs *ReverseFS) newFile(relPath string, flags uint32) (nodefs.File, fuse.S
3546if err != nil {
3647return nil ,fuse .ToStatus (err )
3748}
38- id := derivePathIV (relPath ,ivPurposeFileID )
49+ var st syscall.Stat_t
50+ err = syscall .Fstat (int (fd .Fd ()),& st )
51+ if err != nil {
52+ tlog .Warn .Printf ("newFile: Fstat error: %v" ,err )
53+ return nil ,fuse .ToStatus (err )
54+ }
55+ // See if we have that inode number already in the table
56+ // (even if Nlink has dropped to 1)
57+ var derivedIVs derivedIVContainer
58+ v ,found := inodeTable .Load (st .Ino )
59+ if found {
60+ tlog .Debug .Printf ("ino%d: newFile: found in the inode table" ,st .Ino )
61+ derivedIVs = v .(derivedIVContainer )
62+ }else {
63+ derivedIVs .id = derivePathIV (relPath ,ivPurposeFileID )
64+ derivedIVs .block0IV = derivePathIV (relPath ,ivPurposeBlock0IV )
65+ // Nlink > 1 means there is more than one path to this file.
66+ // Store the derived values so we always return the same data,
67+ // regardless of the path that is used to access the file.
68+ // This means that the first path wins.
69+ if st .Nlink > 1 {
70+ v ,found = inodeTable .LoadOrStore (st .Ino ,derivedIVs )
71+ if found {
72+ // Another thread has stored a different value before we could.
73+ derivedIVs = v .(derivedIVContainer )
74+ }else {
75+ tlog .Debug .Printf ("ino%d: newFile: Nlink=%d, stored in the inode table" ,st .Ino ,st .Nlink )
76+ }
77+ }
78+ }
3979header := contentenc.FileHeader {
4080Version :contentenc .CurrentVersion ,
41- ID :id ,
81+ ID :derivedIVs . id ,
4282}
4383return & reverseFile {
4484File :nodefs .NewDefaultFile (),
4585fd :fd ,
4686header :header ,
47- block0IV :derivePathIV ( relPath , ivPurposeBlock0IV ) ,
87+ block0IV :derivedIVs . block0IV ,
4888contentEnc :rfs .contentEnc ,
4989},fuse .OK
5090}