fusefrontend: support RENAME_WHITEOUT, RENAME_EXCHANGE

Both new internal test and xfstests generic/013 are happy.

https://github.com/rfjakob/gocryptfs/issues/641
This commit is contained in:
Jakob Unterwurzacher 2022-01-22 12:28:27 +01:00
parent 3ca2b1983d
commit b7cac4ffd0
3 changed files with 17 additions and 14 deletions

View File

@ -391,24 +391,18 @@ func (n *Node) Symlink(ctx context.Context, target, name string, out *fuse.Entry
return inode, 0 return inode, 0
} }
// xfstests generic/013 now also exercises RENAME_EXCHANGE and RENAME_WHITEOUT,
// uncovering lots of problems with longnames
//
// Reject those flags with syscall.EINVAL.
// If we can handle the flags, this function returns 0. // If we can handle the flags, this function returns 0.
func rejectRenameFlags(flags uint32) syscall.Errno { func rejectRenameFlags(flags uint32) syscall.Errno {
// Normal rename, we can handle that switch flags {
if flags == 0 { case 0, syscallcompat.RENAME_NOREPLACE, syscallcompat.RENAME_EXCHANGE, syscallcompat.RENAME_WHITEOUT:
return 0 return 0
} case syscallcompat.RENAME_NOREPLACE | syscallcompat.RENAME_WHITEOUT:
// We also can handle RENAME_NOREPLACE
if flags == syscallcompat.RENAME_NOREPLACE {
return 0 return 0
} default:
// We cannot handle RENAME_EXCHANGE and RENAME_WHITEOUT yet. tlog.Warn.Printf("rejectRenameFlags: unknown flag combination 0x%x", flags)
// Needs extra code for .name files.
return syscall.EINVAL return syscall.EINVAL
} }
}
// Rename - FUSE call. // Rename - FUSE call.
// This function is called on the PARENT DIRECTORY of `name`. // This function is called on the PARENT DIRECTORY of `name`.
@ -472,6 +466,11 @@ func (n *Node) Rename(ctx context.Context, name string, newParent fs.InodeEmbedd
} }
return fs.ToErrno(err) return fs.ToErrno(err)
} }
if flags&syscallcompat.RENAME_EXCHANGE != 0 || flags&syscallcompat.RENAME_WHITEOUT != 0 {
// These flags mean that there is now a new file at cName and we
// should NOT delete its longname file.
return 0
}
if nametransform.IsLongContent(cName) { if nametransform.IsLongContent(cName) {
nametransform.DeleteLongNameAt(dirfd, cName) nametransform.DeleteLongNameAt(dirfd, cName)
} }

View File

@ -21,8 +21,10 @@ const (
// O_PATH is only defined on Linux // O_PATH is only defined on Linux
O_PATH = 0 O_PATH = 0
// RENAME_NOREPLACE is only defined on Linux // Only defined on Linux
RENAME_NOREPLACE = 0 RENAME_NOREPLACE = 0
RENAME_WHITEOUT = 0
RENAME_EXCHANGE = 0
// KAUTH_UID_NONE and KAUTH_GID_NONE are special values to // KAUTH_UID_NONE and KAUTH_GID_NONE are special values to
// revert permissions to the process credentials. // revert permissions to the process credentials.

View File

@ -28,8 +28,10 @@ const (
// O_PATH is only defined on Linux // O_PATH is only defined on Linux
O_PATH = unix.O_PATH O_PATH = unix.O_PATH
// RENAME_NOREPLACE is only defined on Linux // Only defined on Linux
RENAME_NOREPLACE = unix.RENAME_NOREPLACE RENAME_NOREPLACE = unix.RENAME_NOREPLACE
RENAME_WHITEOUT = unix.RENAME_WHITEOUT
RENAME_EXCHANGE = unix.RENAME_EXCHANGE
) )
var preallocWarn sync.Once var preallocWarn sync.Once