summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--internal/fusefrontend/node_openbackingdir.go68
-rw-r--r--internal/fusefrontend/root_node.go60
2 files changed, 60 insertions, 68 deletions
diff --git a/internal/fusefrontend/node_openbackingdir.go b/internal/fusefrontend/node_openbackingdir.go
deleted file mode 100644
index 733c239..0000000
--- a/internal/fusefrontend/node_openbackingdir.go
+++ /dev/null
@@ -1,68 +0,0 @@
-package fusefrontend
-
-import (
- "path/filepath"
- "strings"
- "syscall"
-
- "github.com/rfjakob/gocryptfs/internal/nametransform"
- "github.com/rfjakob/gocryptfs/internal/syscallcompat"
-)
-
-// openBackingDir opens the parent ciphertext directory of plaintext path
-// "relPath". It returns the dirfd (opened with O_PATH) and the encrypted
-// basename.
-//
-// The caller should then use Openat(dirfd, cName, ...) and friends.
-// For convenience, if relPath is "", cName is going to be ".".
-//
-// openBackingDir is secure against symlink races by using Openat and
-// ReadDirIVAt.
-func (rn *RootNode) openBackingDir(relPath string) (dirfd int, cName string, err error) {
- dirRelPath := nametransform.Dir(relPath)
- // With PlaintextNames, we don't need to read DirIVs. Easy.
- if rn.args.PlaintextNames {
- dirfd, err = syscallcompat.OpenDirNofollow(rn.args.Cipherdir, dirRelPath)
- if err != nil {
- return -1, "", err
- }
- // If relPath is empty, cName is ".".
- cName = filepath.Base(relPath)
- return dirfd, cName, nil
- }
- // Open cipherdir (following symlinks)
- dirfd, err = syscall.Open(rn.args.Cipherdir, syscall.O_DIRECTORY|syscallcompat.O_PATH, 0)
- if err != nil {
- return -1, "", err
- }
- // If relPath is empty, cName is ".".
- if relPath == "" {
- return dirfd, ".", nil
- }
- // Walk the directory tree
- parts := strings.Split(relPath, "/")
- for i, name := range parts {
- iv, err := nametransform.ReadDirIVAt(dirfd)
- if err != nil {
- syscall.Close(dirfd)
- return -1, "", err
- }
- cName, err = rn.nameTransform.EncryptAndHashName(name, iv)
- if err != nil {
- syscall.Close(dirfd)
- return -1, "", err
- }
- // Last part? We are done.
- if i == len(parts)-1 {
- break
- }
- // Not the last part? Descend into next directory.
- dirfd2, err := syscallcompat.Openat(dirfd, cName, syscall.O_NOFOLLOW|syscall.O_DIRECTORY|syscallcompat.O_PATH, 0)
- syscall.Close(dirfd)
- if err != nil {
- return -1, "", err
- }
- dirfd = dirfd2
- }
- return dirfd, cName, nil
-}
diff --git a/internal/fusefrontend/root_node.go b/internal/fusefrontend/root_node.go
index 2689e05..cf23169 100644
--- a/internal/fusefrontend/root_node.go
+++ b/internal/fusefrontend/root_node.go
@@ -2,6 +2,8 @@ package fusefrontend
import (
"os"
+ "path/filepath"
+ "strings"
"sync"
"sync/atomic"
"syscall"
@@ -185,3 +187,61 @@ func (rn *RootNode) openWriteOnlyFile(dirfd int, cName string, newFlags int) (rw
}()
return syscallcompat.Openat(dirfd, cName, newFlags, 0)
}
+
+// openBackingDir opens the parent ciphertext directory of plaintext path
+// "relPath". It returns the dirfd (opened with O_PATH) and the encrypted
+// basename.
+//
+// The caller should then use Openat(dirfd, cName, ...) and friends.
+// For convenience, if relPath is "", cName is going to be ".".
+//
+// openBackingDir is secure against symlink races by using Openat and
+// ReadDirIVAt.
+func (rn *RootNode) openBackingDir(relPath string) (dirfd int, cName string, err error) {
+ dirRelPath := nametransform.Dir(relPath)
+ // With PlaintextNames, we don't need to read DirIVs. Easy.
+ if rn.args.PlaintextNames {
+ dirfd, err = syscallcompat.OpenDirNofollow(rn.args.Cipherdir, dirRelPath)
+ if err != nil {
+ return -1, "", err
+ }
+ // If relPath is empty, cName is ".".
+ cName = filepath.Base(relPath)
+ return dirfd, cName, nil
+ }
+ // Open cipherdir (following symlinks)
+ dirfd, err = syscall.Open(rn.args.Cipherdir, syscall.O_DIRECTORY|syscallcompat.O_PATH, 0)
+ if err != nil {
+ return -1, "", err
+ }
+ // If relPath is empty, cName is ".".
+ if relPath == "" {
+ return dirfd, ".", nil
+ }
+ // Walk the directory tree
+ parts := strings.Split(relPath, "/")
+ for i, name := range parts {
+ iv, err := nametransform.ReadDirIVAt(dirfd)
+ if err != nil {
+ syscall.Close(dirfd)
+ return -1, "", err
+ }
+ cName, err = rn.nameTransform.EncryptAndHashName(name, iv)
+ if err != nil {
+ syscall.Close(dirfd)
+ return -1, "", err
+ }
+ // Last part? We are done.
+ if i == len(parts)-1 {
+ break
+ }
+ // Not the last part? Descend into next directory.
+ dirfd2, err := syscallcompat.Openat(dirfd, cName, syscall.O_NOFOLLOW|syscall.O_DIRECTORY|syscallcompat.O_PATH, 0)
+ syscall.Close(dirfd)
+ if err != nil {
+ return -1, "", err
+ }
+ dirfd = dirfd2
+ }
+ return dirfd, cName, nil
+}