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.go113
1 files changed, 64 insertions, 49 deletions
diff --git a/internal/fusefrontend_reverse/rfs.go b/internal/fusefrontend_reverse/rfs.go
index 3243dfd..d07971a 100644
--- a/internal/fusefrontend_reverse/rfs.go
+++ b/internal/fusefrontend_reverse/rfs.go
@@ -3,8 +3,7 @@ package fusefrontend_reverse
import (
"fmt"
"os"
- "path"
- "strings"
+ "path/filepath"
"syscall"
"github.com/hanwen/go-fuse/fuse"
@@ -50,47 +49,59 @@ func NewFS(args fusefrontend.Args) *reverseFS {
}
}
-func (rfs *reverseFS) GetAttr(relPath string, context *fuse.Context) (*fuse.Attr, fuse.Status) {
- // Handle gocryptfs.diriv
- if relPath == nametransform.DirIVFilename ||
- strings.HasSuffix(relPath, nametransform.DirIVFilename) {
-
- fmt.Printf("Handling gocryptfs.diriv\n")
-
- cDir := path.Dir(relPath)
- if cDir == "." {
- cDir = ""
- }
- dir, err := rfs.decryptPath(cDir)
- if err != nil {
- fmt.Printf("decrypt err %q\n", cDir)
- return nil, fuse.ToStatus(err)
- }
- // Does the parent dir exist?
- a, status := rfs.loopbackfs.GetAttr(dir, context)
- if !status.Ok() {
- fmt.Printf("missing parent\n")
- return nil, status
- }
- // Is it a dir at all?
- if !a.IsDir() {
- fmt.Printf("not isdir\n")
- return nil, fuse.ENOTDIR
- }
- // Does the user have execute permissions?
- if a.Mode&syscall.S_IXUSR == 0 {
- fmt.Printf("not exec")
- return nil, fuse.EPERM
- }
- // All good. Let's fake the file.
- // We use the inode number of the parent dir (can this cause problems?).
- a.Mode = DirIVMode
- a.Size = nametransform.DirIVLen
- a.Nlink = 1
-
- return a, fuse.OK
+// relDir is identical to filepath.Dir excepts that it returns "" when
+// filepath.Dir would return ".".
+// In the FUSE API, the root directory is called "", and we actually want that.
+func relDir(path string) string {
+ dir := filepath.Dir(path)
+ if dir == "." {
+ return ""
+ }
+ return dir
+}
+
+// dirIVAttr handles GetAttr requests for the virtual gocryptfs.diriv files.
+func (rfs *reverseFS) dirIVAttr(relPath string, context *fuse.Context) (*fuse.Attr, fuse.Status) {
+ cDir := relDir(relPath)
+ dir, err := rfs.decryptPath(cDir)
+ if err != nil {
+ fmt.Printf("decrypt err %q\n", cDir)
+ return nil, fuse.ToStatus(err)
+ }
+ // Does the parent dir exist?
+ a, status := rfs.loopbackfs.GetAttr(dir, context)
+ if !status.Ok() {
+ fmt.Printf("missing parent\n")
+ return nil, status
+ }
+ // Is it a dir at all?
+ if !a.IsDir() {
+ fmt.Printf("not isdir\n")
+ return nil, fuse.ENOTDIR
+ }
+ // Does the user have execute permissions?
+ if a.Mode&syscall.S_IXUSR == 0 {
+ fmt.Printf("not exec")
+ return nil, fuse.EPERM
}
+ // All good. Let's fake the file.
+ // We use the inode number of the parent dir (can this cause problems?).
+ a.Mode = DirIVMode
+ a.Size = nametransform.DirIVLen
+ a.Nlink = 1
+ return a, fuse.OK
+}
+
+// isDirIV determines if the path points to a gocryptfs.diriv file
+func isDirIV(relPath string) bool {
+ return filepath.Base(relPath) == nametransform.DirIVFilename
+}
+
+func (rfs *reverseFS) GetAttr(relPath string, context *fuse.Context) (*fuse.Attr, fuse.Status) {
+ if isDirIV(relPath) {
+ return rfs.dirIVAttr(relPath, context)
+ }
if rfs.isFiltered(relPath) {
return nil, fuse.EPERM
}
@@ -110,17 +121,23 @@ func (rfs *reverseFS) GetAttr(relPath string, context *fuse.Context) (*fuse.Attr
}
func (rfs *reverseFS) Access(relPath string, mode uint32, context *fuse.Context) fuse.Status {
+ if isDirIV(relPath) {
+ return fuse.OK
+ }
if rfs.isFiltered(relPath) {
return fuse.EPERM
}
- cPath, err := rfs.abs(rfs.encryptPath(relPath))
+ absPath, err := rfs.abs(rfs.decryptPath(relPath))
if err != nil {
return fuse.ToStatus(err)
}
- return fuse.ToStatus(syscall.Access(cPath, mode))
+ return fuse.ToStatus(syscall.Access(absPath, mode))
}
func (rfs *reverseFS) Open(relPath string, flags uint32, context *fuse.Context) (fuseFile nodefs.File, status fuse.Status) {
+ if isDirIV(relPath) {
+ return NewDirIVFile(relPath)
+ }
if rfs.isFiltered(relPath) {
return nil, fuse.EPERM
}
@@ -135,8 +152,8 @@ func (rfs *reverseFS) Open(relPath string, flags uint32, context *fuse.Context)
return NewFile(f, rfs.contentEnc)
}
-func (rfs *reverseFS) OpenDir(relPath string, context *fuse.Context) ([]fuse.DirEntry, fuse.Status) {
- relPath, err := rfs.decryptPath(relPath)
+func (rfs *reverseFS) OpenDir(cipherPath string, context *fuse.Context) ([]fuse.DirEntry, fuse.Status) {
+ relPath, err := rfs.decryptPath(cipherPath)
if err != nil {
return nil, fuse.ToStatus(err)
}
@@ -146,11 +163,9 @@ func (rfs *reverseFS) OpenDir(relPath string, context *fuse.Context) ([]fuse.Dir
return nil, status
}
// Encrypt names
+ dirIV := deriveDirIV(cipherPath)
for i := range entries {
- entries[i].Name, err = rfs.encryptPath(entries[i].Name)
- if err != nil {
- return nil, fuse.ToStatus(err)
- }
+ entries[i].Name = rfs.nameTransform.EncryptName(entries[i].Name, dirIV)
}
// Add virtual gocryptfs.diriv
entries = append(entries, fuse.DirEntry{syscall.S_IFREG | 0400, nametransform.DirIVFilename})