01ccf204f4
Before this change, if writing to a local backend with --metadata and --links, if the incoming metadata contained mode or ownership information then rclone would apply the mode/ownership to the destination of the link not the link itself. This fixes the problem by using the link safe sycall variants lchown/fchmodat when --links and --metadata is in use. Note that Linux does not support setting permissions on symlinks, so rclone emits a debug message in this case. This also fixes setting times on symlinks on Windows which wasn't implemented for atime, mtime and was incorrectly setting the target of the symlink for btime. See: https://github.com/rclone/rclone/security/advisories/GHSA-hrxh-9w67-g4cv
41 lines
1.1 KiB
Go
41 lines
1.1 KiB
Go
//go:build !windows && !plan9 && !js && !linux
|
|
|
|
package local
|
|
|
|
import (
|
|
"os"
|
|
"syscall"
|
|
|
|
"golang.org/x/sys/unix"
|
|
)
|
|
|
|
const haveLChmod = true
|
|
|
|
// syscallMode returns the syscall-specific mode bits from Go's portable mode bits.
|
|
//
|
|
// Borrowed from the syscall source since it isn't public.
|
|
func syscallMode(i os.FileMode) (o uint32) {
|
|
o |= uint32(i.Perm())
|
|
if i&os.ModeSetuid != 0 {
|
|
o |= syscall.S_ISUID
|
|
}
|
|
if i&os.ModeSetgid != 0 {
|
|
o |= syscall.S_ISGID
|
|
}
|
|
if i&os.ModeSticky != 0 {
|
|
o |= syscall.S_ISVTX
|
|
}
|
|
return o
|
|
}
|
|
|
|
// lChmod changes the mode of the named file to mode. If the file is a symbolic
|
|
// link, it changes the link, not the target. If there is an error,
|
|
// it will be of type *PathError.
|
|
func lChmod(name string, mode os.FileMode) error {
|
|
// NB linux does not support AT_SYMLINK_NOFOLLOW as a parameter to fchmodat
|
|
// and returns ENOTSUP if you try, so we don't support this on linux
|
|
if e := unix.Fchmodat(unix.AT_FDCWD, name, syscallMode(mode), unix.AT_SYMLINK_NOFOLLOW); e != nil {
|
|
return &os.PathError{Op: "lChmod", Path: name, Err: e}
|
|
}
|
|
return nil
|
|
}
|