aboutsummaryrefslogtreecommitdiff
path: root/internal/fusefrontend_reverse/rfs.go
diff options
context:
space:
mode:
Diffstat (limited to 'internal/fusefrontend_reverse/rfs.go')
-rw-r--r--internal/fusefrontend_reverse/rfs.go94
1 files changed, 35 insertions, 59 deletions
diff --git a/internal/fusefrontend_reverse/rfs.go b/internal/fusefrontend_reverse/rfs.go
index 18f7506..a94f448 100644
--- a/internal/fusefrontend_reverse/rfs.go
+++ b/internal/fusefrontend_reverse/rfs.go
@@ -5,7 +5,6 @@ import (
"log"
"os"
"path/filepath"
- "sync"
"syscall"
"github.com/hanwen/go-fuse/fuse"
@@ -20,12 +19,6 @@ import (
"github.com/rfjakob/gocryptfs/internal/tlog"
)
-const (
- // virtualFileMode is the mode to use for virtual files (gocryptfs.diriv and gocryptfs.longname.*.name)
- // they are always readable, as stated in func Access
- virtualFileMode = syscall.S_IFREG | 0444
-)
-
// ReverseFS implements the pathfs.FileSystem interface and provides an
// encrypted view of a plaintext directory.
type ReverseFS struct {
@@ -39,12 +32,6 @@ type ReverseFS struct {
nameTransform *nametransform.NameTransform
// Content encryption helper
contentEnc *contentenc.ContentEnc
- // Inode number generator
- inoGen *inoGenT
- // Maps backing files device+inode pairs to user-facing unique inode numbers
- inoMap map[fusefrontend.DevInoStruct]uint64
- // Protects map access
- inoMapLock sync.Mutex
}
var _ pathfs.FileSystem = &ReverseFS{}
@@ -68,8 +55,6 @@ func NewFS(args fusefrontend.Args) *ReverseFS {
args: args,
nameTransform: nameTransform,
contentEnc: contentEnc,
- inoGen: newInoGen(),
- inoMap: map[fusefrontend.DevInoStruct]uint64{},
}
}
@@ -102,7 +87,7 @@ func (rfs *ReverseFS) isNameFile(relPath string) bool {
return fileType == nametransform.LongNameFilename
}
-// isTranslatedConfig returns true if the default config file name is in
+// isTranslatedConfig returns true if the default config file name is in use
// and the ciphertext path is "gocryptfs.conf".
// "gocryptfs.conf" then maps to ".gocryptfs.reverse.conf" in the plaintext
// directory.
@@ -116,47 +101,22 @@ func (rfs *ReverseFS) isTranslatedConfig(relPath string) bool {
return false
}
-func (rfs *ReverseFS) inoAwareStat(relPlainPath string) (*fuse.Attr, fuse.Status) {
- absPath, err := rfs.abs(relPlainPath, nil)
- if err != nil {
- return nil, fuse.ToStatus(err)
- }
- var fi os.FileInfo
- if relPlainPath == "" {
- // Look through symlinks for the root dir
- fi, err = os.Stat(absPath)
- } else {
- fi, err = os.Lstat(absPath)
- }
- if err != nil {
- return nil, fuse.ToStatus(err)
- }
- st := fi.Sys().(*syscall.Stat_t)
- // The file has hard links. We have to give it a stable inode number so
- // tar or rsync can find them.
- if fi.Mode().IsRegular() && st.Nlink > 1 {
- di := fusefrontend.DevInoFromStat(st)
- rfs.inoMapLock.Lock()
- stableIno := rfs.inoMap[di]
- if stableIno == 0 {
- rfs.inoMap[di] = rfs.inoGen.next()
- }
- rfs.inoMapLock.Unlock()
- st.Ino = stableIno
- } else {
- st.Ino = rfs.inoGen.next()
- }
- a := &fuse.Attr{}
- a.FromStat(st)
- return a, fuse.OK
-}
-
// GetAttr - FUSE call
+// "relPath" is the relative ciphertext path
func (rfs *ReverseFS) GetAttr(relPath string, context *fuse.Context) (*fuse.Attr, fuse.Status) {
+ // Handle "gocryptfs.conf"
if rfs.isTranslatedConfig(relPath) {
- return rfs.inoAwareStat(configfile.ConfReverseName)
+ absConfPath, _ := rfs.abs(configfile.ConfReverseName, nil)
+ var st syscall.Stat_t
+ err := syscall.Lstat(absConfPath, &st)
+ if err != nil {
+ return nil, fuse.ToStatus(err)
+ }
+ var a fuse.Attr
+ a.FromStat(&st)
+ return &a, fuse.OK
}
- // Handle virtual files
+ // Handle virtual files (gocryptfs.diriv, *.name)
var f nodefs.File
var status fuse.Status
virtual := false
@@ -177,15 +137,31 @@ func (rfs *ReverseFS) GetAttr(relPath string, context *fuse.Context) (*fuse.Attr
status = f.GetAttr(&a)
return &a, status
}
-
- cPath, err := rfs.decryptPath(relPath)
+ // Decrypt path to "plaintext relative path"
+ pRelPath, err := rfs.decryptPath(relPath)
if err != nil {
return nil, fuse.ToStatus(err)
}
- a, status := rfs.inoAwareStat(cPath)
- if !status.Ok() {
- return nil, status
+ absPath, _ := rfs.abs(pRelPath, nil)
+ // Stat the backing file
+ var st syscall.Stat_t
+ if relPath == "" {
+ // Look through symlinks for the root dir
+ err = syscall.Stat(absPath, &st)
+ } else {
+ err = syscall.Lstat(absPath, &st)
+ }
+ if err != nil {
+ return nil, fuse.ToStatus(err)
+ }
+ // Instead of risking an inode number collision, we return an error.
+ if st.Ino > virtualInoBase {
+ tlog.Warn.Printf("GetAttr %q: backing file inode number %d crosses reserved space, max=%d. Returning EOVERFLOW.",
+ relPath, st.Ino, virtualInoBase)
+ return nil, fuse.ToStatus(syscall.EOVERFLOW)
}
+ var a fuse.Attr
+ a.FromStat(&st)
// Calculate encrypted file size
if a.IsRegular() {
a.Size = rfs.contentEnc.PlainSizeToCipherSize(a.Size)
@@ -200,7 +176,7 @@ func (rfs *ReverseFS) GetAttr(relPath string, context *fuse.Context) (*fuse.Attr
a.Size = uint64(len(linkTarget))
}
- return a, fuse.OK
+ return &a, fuse.OK
}
// Access - FUSE call