Skip to content

Commit

Permalink
fusefrontend_reverse: store derived values for hard-linked files
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
rfjakob committed May 25, 2017
1 parent bfc8d47 commit 9ecf2d1
Showing 1 changed file with 43 additions and 3 deletions.
46 changes: 43 additions & 3 deletions internal/fusefrontend_reverse/rfile.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -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 {
Expand All @@ -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
}
Expand Down

0 comments on commit 9ecf2d1

Please sign in to comment.