diff options
Diffstat (limited to 'internal')
| -rw-r--r-- | internal/fusefrontend/fs_dir.go | 51 | 
1 files changed, 28 insertions, 23 deletions
| diff --git a/internal/fusefrontend/fs_dir.go b/internal/fusefrontend/fs_dir.go index d26fd79..35aae66 100644 --- a/internal/fusefrontend/fs_dir.go +++ b/internal/fusefrontend/fs_dir.go @@ -151,42 +151,47 @@ func (fs *FS) Rmdir(relPath string, context *fuse.Context) (code fuse.Status) {  		err = unix.Unlinkat(parentDirFd, cName, unix.AT_REMOVEDIR)  		return fuse.ToStatus(err)  	} -	dirfd, err := syscallcompat.Openat(parentDirFd, cName, -		syscall.O_RDONLY|syscall.O_DIRECTORY|syscall.O_NOFOLLOW, 0) -	if err == syscall.EACCES { -		// We need permission to read and modify the directory -		tlog.Debug.Printf("Rmdir: handling EACCESS") +	// Unless we are running as root, we need read, write and execute permissions +	// to handle gocryptfs.diriv. +	permWorkaround := false +	var origMode uint32 +	if !fs.args.PreserveOwner {  		var st unix.Stat_t  		err = syscallcompat.Fstatat(parentDirFd, cName, &st, unix.AT_SYMLINK_NOFOLLOW)  		if err != nil { -			tlog.Debug.Printf("Rmdir: Stat: %v", err)  			return fuse.ToStatus(err)  		} -		// This cast is needed on Darwin, where st.Mode is uint16. -		origMode := uint32(st.Mode) -		err = syscallcompat.FchmodatNofollow(parentDirFd, cName, origMode|0700) -		if err != nil { -			tlog.Debug.Printf("Rmdir: Fchmodat failed: %v", err) -			return fuse.ToStatus(err) +		if st.Mode&0700 != 0700 { +			tlog.Debug.Printf("Rmdir: permWorkaround") +			permWorkaround = true +			// This cast is needed on Darwin, where st.Mode is uint16. +			origMode = uint32(st.Mode) +			err = syscallcompat.FchmodatNofollow(parentDirFd, cName, origMode|0700) +			if err != nil { +				tlog.Debug.Printf("Rmdir: permWorkaround: chmod failed: %v", err) +				return fuse.ToStatus(err) +			}  		} -		// Retry open -		dirfd, err = syscallcompat.Openat(parentDirFd, cName, -			syscall.O_RDONLY|syscall.O_DIRECTORY|syscall.O_NOFOLLOW, 0) -		// Undo the chmod if removing the directory failed +	} +	dirfd, err := syscallcompat.Openat(parentDirFd, cName, +		syscall.O_RDONLY|syscall.O_DIRECTORY|syscall.O_NOFOLLOW, 0) +	if err != nil { +		tlog.Debug.Printf("Rmdir: Open: %v", err) +		return fuse.ToStatus(err) +	} +	defer syscall.Close(dirfd) +	// Undo the chmod if removing the directory failed. This must run before +	// closing dirfd, so defer it after (defer is LIFO). +	if permWorkaround {  		defer func() {  			if code != fuse.OK { -				err = syscallcompat.FchmodatNofollow(parentDirFd, cName, origMode) +				err = unix.Fchmod(dirfd, origMode)  				if err != nil { -					tlog.Warn.Printf("Rmdir: Chmod rollback failed: %v", err) +					tlog.Warn.Printf("Rmdir: permWorkaround: rollback failed: %v", err)  				}  			}  		}()  	} -	if err != nil { -		tlog.Debug.Printf("Rmdir: Open: %v", err) -		return fuse.ToStatus(err) -	} -	defer syscall.Close(dirfd)  retry:  	// Check directory contents  	children, err := syscallcompat.Getdents(dirfd) | 
