diff options
Diffstat (limited to 'internal/fusefrontend_reverse')
| -rw-r--r-- | internal/fusefrontend_reverse/rfile.go | 46 | 
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  } | 
