aboutsummaryrefslogtreecommitdiff
path: root/internal/fusefrontend
diff options
context:
space:
mode:
authorJakob Unterwurzacher2021-08-20 10:57:26 +0200
committerJakob Unterwurzacher2021-08-20 10:58:42 +0200
commit195d9d18a90d88ff2cb0530d832c59d98934fd1f (patch)
treee226de2355cfdf3f2d3a26411b85a338f2a264ef /internal/fusefrontend
parent8f94083a2114c3aef4bc0320065e0374c420ea4a (diff)
Implement -deterministic-names: extended -zerodiriv
-deterministc-names uses all-zero dirivs but does not write them to disk anymore.
Diffstat (limited to 'internal/fusefrontend')
-rw-r--r--internal/fusefrontend/args.go4
-rw-r--r--internal/fusefrontend/ctlsock_interface.go4
-rw-r--r--internal/fusefrontend/node_dir_ops.go111
-rw-r--r--internal/fusefrontend/node_prepare_syscall.go3
-rw-r--r--internal/fusefrontend/xattr_unit_test.go2
5 files changed, 71 insertions, 53 deletions
diff --git a/internal/fusefrontend/args.go b/internal/fusefrontend/args.go
index 02ffddb..e20987b 100644
--- a/internal/fusefrontend/args.go
+++ b/internal/fusefrontend/args.go
@@ -53,6 +53,6 @@ type Args struct {
// like rsync's `--one-file-system` does.
// Only applicable to reverse mode.
OneFileSystem bool
- // ZeroDirIV creates diriv files as all-zero files
- ZeroDirIV bool
+ // DeterministicNames disables gocryptfs.diriv files
+ DeterministicNames bool
}
diff --git a/internal/fusefrontend/ctlsock_interface.go b/internal/fusefrontend/ctlsock_interface.go
index 9e8cffc..87f0dc3 100644
--- a/internal/fusefrontend/ctlsock_interface.go
+++ b/internal/fusefrontend/ctlsock_interface.go
@@ -32,7 +32,7 @@ func (rn *RootNode) EncryptPath(plainPath string) (cipherPath string, err error)
parts := strings.Split(plainPath, "/")
wd := dirfd
for i, part := range parts {
- dirIV, err := nametransform.ReadDirIVAt(wd)
+ dirIV, err := rn.nameTransform.ReadDirIVAt(wd)
if err != nil {
return "", err
}
@@ -78,7 +78,7 @@ func (rn *RootNode) DecryptPath(cipherPath string) (plainPath string, err error)
parts := strings.Split(cipherPath, "/")
wd := dirfd
for i, part := range parts {
- dirIV, err := nametransform.ReadDirIVAt(wd)
+ dirIV, err := rn.nameTransform.ReadDirIVAt(wd)
if err != nil {
return "", err
}
diff --git a/internal/fusefrontend/node_dir_ops.go b/internal/fusefrontend/node_dir_ops.go
index b43a4e4..c4ab861 100644
--- a/internal/fusefrontend/node_dir_ops.go
+++ b/internal/fusefrontend/node_dir_ops.go
@@ -34,9 +34,14 @@ func haveDsstore(entries []fuse.DirEntry) bool {
// mkdirWithIv - create a new directory and corresponding diriv file. dirfd
// should be a handle to the parent directory, cName is the name of the new
// directory and mode specifies the access permissions to use.
+// If DeterministicNames is set, the diriv file is NOT created.
func (n *Node) mkdirWithIv(dirfd int, cName string, mode uint32, context *fuse.Context) error {
-
rn := n.rootNode()
+
+ if rn.args.DeterministicNames {
+ return syscallcompat.MkdiratUser(dirfd, cName, mode, context)
+ }
+
// Between the creation of the directory and the creation of gocryptfs.diriv
// the directory is inconsistent. Take the lock to prevent other readers
// from seeing it.
@@ -49,7 +54,7 @@ func (n *Node) mkdirWithIv(dirfd int, cName string, mode uint32, context *fuse.C
dirfd2, err := syscallcompat.Openat(dirfd, cName, syscall.O_DIRECTORY|syscall.O_NOFOLLOW|syscallcompat.O_PATH, 0)
if err == nil {
// Create gocryptfs.diriv
- err = nametransform.WriteDirIVAt(dirfd2, !rn.args.ZeroDirIV)
+ err = nametransform.WriteDirIVAt(dirfd2)
syscall.Close(dirfd2)
}
if err != nil {
@@ -90,62 +95,67 @@ func (n *Node) Mkdir(ctx context.Context, name string, mode uint32, out *fuse.En
return nil, fs.ToErrno(err)
}
st = syscallcompat.Unix2syscall(ust)
- } else {
- // We need write and execute permissions to create gocryptfs.diriv.
- // Also, we need read permissions to open the directory (to avoid
- // race-conditions between getting and setting the mode).
- origMode := mode
- mode = mode | 0700
- // Handle long file name
- if nametransform.IsLongContent(cName) {
- // Create ".name"
- err := rn.nameTransform.WriteLongNameAt(dirfd, cName, name)
- if err != nil {
- return nil, fs.ToErrno(err)
- }
+ // Create child node & return
+ ch := n.newChild(ctx, &st, out)
+ return ch, 0
- // Create directory
- err = rn.mkdirWithIv(dirfd, cName, mode, context)
- if err != nil {
- nametransform.DeleteLongNameAt(dirfd, cName)
- return nil, fs.ToErrno(err)
- }
- } else {
- err := rn.mkdirWithIv(dirfd, cName, mode, context)
- if err != nil {
- return nil, fs.ToErrno(err)
- }
- }
+ }
+
+ // We need write and execute permissions to create gocryptfs.diriv.
+ // Also, we need read permissions to open the directory (to avoid
+ // race-conditions between getting and setting the mode).
+ origMode := mode
+ mode = mode | 0700
- fd, err := syscallcompat.Openat(dirfd, cName,
- syscall.O_RDONLY|syscall.O_DIRECTORY|syscall.O_NOFOLLOW, 0)
+ // Handle long file name
+ if nametransform.IsLongContent(cName) {
+ // Create ".name"
+ err := rn.nameTransform.WriteLongNameAt(dirfd, cName, name)
if err != nil {
- tlog.Warn.Printf("Mkdir %q: Openat failed: %v", cName, err)
return nil, fs.ToErrno(err)
}
- defer syscall.Close(fd)
-
- err = syscall.Fstat(fd, &st)
+ // Create directory & rollback .name file on error
+ err = rn.mkdirWithIv(dirfd, cName, mode, context)
+ if err != nil {
+ nametransform.DeleteLongNameAt(dirfd, cName)
+ return nil, fs.ToErrno(err)
+ }
+ } else {
+ err := rn.mkdirWithIv(dirfd, cName, mode, context)
if err != nil {
- tlog.Warn.Printf("Mkdir %q: Fstat failed: %v", cName, err)
return nil, fs.ToErrno(err)
}
+ }
- // Fix permissions
- if origMode != mode {
- // Preserve SGID bit if it was set due to inheritance.
- origMode = uint32(st.Mode&^0777) | origMode
- err = syscall.Fchmod(fd, origMode)
- if err != nil {
- tlog.Warn.Printf("Mkdir %q: Fchmod %#o -> %#o failed: %v", cName, mode, origMode, err)
- }
+ // Fill `st`
+ fd, err := syscallcompat.Openat(dirfd, cName,
+ syscall.O_RDONLY|syscall.O_DIRECTORY|syscall.O_NOFOLLOW, 0)
+ if err != nil {
+ tlog.Warn.Printf("Mkdir %q: Openat failed: %v", cName, err)
+ return nil, fs.ToErrno(err)
+ }
+ defer syscall.Close(fd)
+
+ err = syscall.Fstat(fd, &st)
+ if err != nil {
+ tlog.Warn.Printf("Mkdir %q: Fstat failed: %v", cName, err)
+ return nil, fs.ToErrno(err)
+ }
+
+ // Fix permissions
+ if origMode != mode {
+ // Preserve SGID bit if it was set due to inheritance.
+ origMode = uint32(st.Mode&^0777) | origMode
+ err = syscall.Fchmod(fd, origMode)
+ if err != nil {
+ tlog.Warn.Printf("Mkdir %q: Fchmod %#o -> %#o failed: %v", cName, mode, origMode, err)
}
+
}
- // Create child node
+ // Create child node & return
ch := n.newChild(ctx, &st, out)
-
return ch, 0
}
@@ -175,7 +185,7 @@ func (n *Node) Readdir(ctx context.Context) (fs.DirStream, syscall.Errno) {
rn := n.rootNode()
if !rn.args.PlaintextNames {
// Read the DirIV from disk
- cachedIV, err = nametransform.ReadDirIVAt(fd)
+ cachedIV, err = rn.nameTransform.ReadDirIVAt(fd)
if err != nil {
tlog.Warn.Printf("OpenDir %q: could not read %s: %v", cDirName, nametransform.DirIVFilename, err)
return nil, syscall.EIO
@@ -196,7 +206,7 @@ func (n *Node) Readdir(ctx context.Context) (fs.DirStream, syscall.Errno) {
plain = append(plain, cipherEntries[i])
continue
}
- if cName == nametransform.DirIVFilename {
+ if !rn.args.DeterministicNames && cName == nametransform.DirIVFilename {
// silently ignore "gocryptfs.diriv" everywhere if dirIV is enabled
continue
}
@@ -249,6 +259,15 @@ func (n *Node) Rmdir(ctx context.Context, name string) (code syscall.Errno) {
err := unix.Unlinkat(parentDirFd, cName, unix.AT_REMOVEDIR)
return fs.ToErrno(err)
}
+ if rn.args.DeterministicNames {
+ if err := unix.Unlinkat(parentDirFd, cName, unix.AT_REMOVEDIR); err != nil {
+ return fs.ToErrno(err)
+ }
+ if nametransform.IsLongContent(cName) {
+ nametransform.DeleteLongNameAt(parentDirFd, cName)
+ }
+ return 0
+ }
// Unless we are running as root, we need read, write and execute permissions
// to handle gocryptfs.diriv.
permWorkaround := false
diff --git a/internal/fusefrontend/node_prepare_syscall.go b/internal/fusefrontend/node_prepare_syscall.go
index 0894379..8a0e75c 100644
--- a/internal/fusefrontend/node_prepare_syscall.go
+++ b/internal/fusefrontend/node_prepare_syscall.go
@@ -8,7 +8,6 @@ import (
"github.com/hanwen/go-fuse/v2/fs"
- "github.com/rfjakob/gocryptfs/internal/nametransform"
"github.com/rfjakob/gocryptfs/internal/syscallcompat"
)
@@ -73,7 +72,7 @@ func (n *Node) prepareAtSyscall(child string) (dirfd int, cName string, errno sy
// Cache store
if !rn.args.PlaintextNames {
var err error
- iv, err = nametransform.ReadDirIVAt(dirfd)
+ iv, err = rn.nameTransform.ReadDirIVAt(dirfd)
if err != nil {
syscall.Close(dirfd)
return -1, "", fs.ToErrno(err)
diff --git a/internal/fusefrontend/xattr_unit_test.go b/internal/fusefrontend/xattr_unit_test.go
index c48781c..397e3ef 100644
--- a/internal/fusefrontend/xattr_unit_test.go
+++ b/internal/fusefrontend/xattr_unit_test.go
@@ -19,7 +19,7 @@ func newTestFS(args Args) *RootNode {
key := make([]byte, cryptocore.KeyLen)
cCore := cryptocore.New(key, cryptocore.BackendGoGCM, contentenc.DefaultIVBits, true, false)
cEnc := contentenc.New(cCore, contentenc.DefaultBS, false)
- n := nametransform.New(cCore.EMECipher, true, true, nil)
+ n := nametransform.New(cCore.EMECipher, true, true, nil, false)
rn := NewRootNode(args, cEnc, n)
oneSec := time.Second
options := &fs.Options{