diff options
author | Jakob Unterwurzacher | 2017-05-25 21:33:16 +0200 |
---|---|---|
committer | Jakob Unterwurzacher | 2017-05-25 21:33:16 +0200 |
commit | 9ecf2d1a3f69e3d995012073afe3fc664bd928f2 (patch) | |
tree | 7fb5ae498a58cfbafc04a0f856b15f5a41c3ba1c | |
parent | bfc8d47747f8dee2528b2e505e69fbb106edaddc (diff) |
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.
-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 } |