aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--internal/fusefrontend_reverse/rfile.go27
-rw-r--r--internal/fusefrontend_reverse/rfs.go93
-rw-r--r--internal/fusefrontend_reverse/rpath.go56
3 files changed, 176 insertions, 0 deletions
diff --git a/internal/fusefrontend_reverse/rfile.go b/internal/fusefrontend_reverse/rfile.go
new file mode 100644
index 0000000..746a0d6
--- /dev/null
+++ b/internal/fusefrontend_reverse/rfile.go
@@ -0,0 +1,27 @@
+package fusefrontend_reverse
+
+import (
+ "os"
+
+ "github.com/hanwen/go-fuse/fuse"
+ "github.com/hanwen/go-fuse/fuse/nodefs"
+
+ "github.com/rfjakob/gocryptfs/internal/contentenc"
+)
+
+type file struct {
+ fd *os.File
+ // Content encryption helper
+ contentEnc *contentenc.ContentEnc
+
+ // nodefs.defaultFile returns ENOSYS for all operations
+ nodefs.File
+}
+
+func NewFile(fd *os.File, contentEnc *contentenc.ContentEnc) (nodefs.File, fuse.Status) {
+ return &file{
+ fd: fd,
+ contentEnc: contentEnc,
+ File: nodefs.NewDefaultFile(),
+ }, fuse.OK
+}
diff --git a/internal/fusefrontend_reverse/rfs.go b/internal/fusefrontend_reverse/rfs.go
new file mode 100644
index 0000000..914dccb
--- /dev/null
+++ b/internal/fusefrontend_reverse/rfs.go
@@ -0,0 +1,93 @@
+package fusefrontend_reverse
+
+import (
+ "os"
+
+ "github.com/hanwen/go-fuse/fuse"
+ "github.com/hanwen/go-fuse/fuse/nodefs"
+ "github.com/hanwen/go-fuse/fuse/pathfs"
+
+ "github.com/rfjakob/gocryptfs/internal/contentenc"
+ "github.com/rfjakob/gocryptfs/internal/cryptocore"
+ "github.com/rfjakob/gocryptfs/internal/fusefrontend"
+ "github.com/rfjakob/gocryptfs/internal/nametransform"
+)
+
+type FS struct {
+ // loopbackFileSystem, see go-fuse/fuse/pathfs/loopback.go
+ pathfs.FileSystem
+ // Stores configuration arguments
+ args fusefrontend.Args
+ // Filename encryption helper
+ nameTransform *nametransform.NameTransform
+ // Content encryption helper
+ contentEnc *contentenc.ContentEnc
+}
+
+// Encrypted FUSE overlay filesystem
+func NewFS(args fusefrontend.Args) *FS {
+ cryptoCore := cryptocore.New(args.Masterkey, args.OpenSSL, true)
+ contentEnc := contentenc.New(cryptoCore, contentenc.DefaultBS)
+ nameTransform := nametransform.New(cryptoCore, args.LongNames)
+
+ return &FS{
+ FileSystem: pathfs.NewLoopbackFileSystem(args.Cipherdir),
+ args: args,
+ nameTransform: nameTransform,
+ contentEnc: contentEnc,
+ }
+}
+
+func (fs *FS) GetAttr(relPath string, context *fuse.Context) (*fuse.Attr, fuse.Status) {
+ if fs.isFiltered(relPath) {
+ return nil, fuse.EPERM
+ }
+ relPath, err := fs.decryptPath(relPath)
+ if err != nil {
+ return nil, fuse.ToStatus(err)
+ }
+ a, status := fs.FileSystem.GetAttr(relPath, context)
+ if a == nil {
+ return a, status
+ }
+ // Calculate encrypted file size
+ if a.IsRegular() {
+ a.Size = fs.contentEnc.PlainSizeToCipherSize(a.Size)
+ }
+ return a, fuse.OK
+}
+
+func (fs *FS) Open(relPath string, flags uint32, context *fuse.Context) (fuseFile nodefs.File, status fuse.Status) {
+ if fs.isFiltered(relPath) {
+ return nil, fuse.EPERM
+ }
+ absPath, err := fs.abs(fs.decryptPath(relPath))
+ if err != nil {
+ return nil, fuse.ToStatus(err)
+ }
+ f, err := os.OpenFile(absPath, int(flags), 0666)
+ if err != nil {
+ return nil, fuse.ToStatus(err)
+ }
+ return NewFile(f, fs.contentEnc)
+}
+
+func (fs *FS) OpenDir(relPath string, context *fuse.Context) ([]fuse.DirEntry, fuse.Status) {
+ relPath, err := fs.decryptPath(relPath)
+ if err != nil {
+ return nil, fuse.ToStatus(err)
+ }
+ // Read plaintext dir
+ entries, status := fs.FileSystem.OpenDir(relPath, context)
+ if entries == nil {
+ return nil, status
+ }
+ // Encrypt names
+ for i := range entries {
+ entries[i].Name, err = fs.encryptPath(entries[i].Name)
+ if err != nil {
+ return nil, fuse.ToStatus(err)
+ }
+ }
+ return entries, fuse.OK
+}
diff --git a/internal/fusefrontend_reverse/rpath.go b/internal/fusefrontend_reverse/rpath.go
new file mode 100644
index 0000000..9377958
--- /dev/null
+++ b/internal/fusefrontend_reverse/rpath.go
@@ -0,0 +1,56 @@
+package fusefrontend_reverse
+
+import (
+ "path/filepath"
+ "strings"
+)
+
+func (fs *FS) abs(relPath string, err error) (string, error) {
+ if err != nil {
+ return "", err
+ }
+ return filepath.Join(fs.args.Cipherdir, relPath), nil
+}
+
+const (
+ ENCRYPT = iota
+ DECRYPT
+)
+
+func (fs *FS) encryptPath(relPath string) (string, error) {
+ return fs.transformPath(relPath, ENCRYPT)
+}
+
+func (fs *FS) decryptPath(relPath string) (string, error) {
+ return fs.transformPath(relPath, DECRYPT)
+}
+
+func (fs *FS) transformPath(relPath string, direction int) (string, error) {
+ if fs.args.PlaintextNames {
+ return relPath, nil
+ }
+ var err error
+ var transformedParts []string
+ iv := make([]byte, 16)
+ parts := strings.Split(relPath, "/")
+ for _, part := range parts {
+ var transformedPart string
+ switch direction {
+ case ENCRYPT:
+ transformedPart = fs.nameTransform.EncryptName(part, iv)
+ case DECRYPT:
+ transformedPart, err = fs.nameTransform.DecryptName(part, iv)
+ if err != nil {
+ return "", err
+ }
+ default:
+ panic("bug: invalid direction value")
+ }
+ transformedParts = append(transformedParts, transformedPart)
+ }
+ return filepath.Join(transformedParts...), nil
+}
+
+func (fs *FS) isFiltered(relPath string) bool {
+ return false
+}