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.
This commit is contained in:
Jakob Unterwurzacher 2017-05-25 21:33:16 +02:00
parent bfc8d47747
commit 9ecf2d1a3f

View File

@ -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
}