diff options
| author | Jakob Unterwurzacher | 2021-08-20 10:57:26 +0200 | 
|---|---|---|
| committer | Jakob Unterwurzacher | 2021-08-20 10:58:42 +0200 | 
| commit | 195d9d18a90d88ff2cb0530d832c59d98934fd1f (patch) | |
| tree | e226de2355cfdf3f2d3a26411b85a338f2a264ef /internal/fusefrontend | |
| parent | 8f94083a2114c3aef4bc0320065e0374c420ea4a (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.go | 4 | ||||
| -rw-r--r-- | internal/fusefrontend/ctlsock_interface.go | 4 | ||||
| -rw-r--r-- | internal/fusefrontend/node_dir_ops.go | 111 | ||||
| -rw-r--r-- | internal/fusefrontend/node_prepare_syscall.go | 3 | ||||
| -rw-r--r-- | internal/fusefrontend/xattr_unit_test.go | 2 | 
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{ | 
