mirror of
https://github.com/rclone/rclone.git
synced 2024-12-21 19:16:29 +08:00
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
60 lines
1.4 KiB
Go
60 lines
1.4 KiB
Go
//go:build windows
|
|
|
|
package local
|
|
|
|
import (
|
|
"syscall"
|
|
"time"
|
|
)
|
|
|
|
const haveSetBTime = true
|
|
|
|
// setTimes sets any of atime, mtime or btime
|
|
// if link is set it sets a link rather than the target
|
|
func setTimes(name string, atime, mtime, btime time.Time, link bool) (err error) {
|
|
pathp, err := syscall.UTF16PtrFromString(name)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
fileFlag := uint32(syscall.FILE_FLAG_BACKUP_SEMANTICS)
|
|
if link {
|
|
fileFlag |= syscall.FILE_FLAG_OPEN_REPARSE_POINT
|
|
}
|
|
h, err := syscall.CreateFile(pathp,
|
|
syscall.FILE_WRITE_ATTRIBUTES, syscall.FILE_SHARE_WRITE, nil,
|
|
syscall.OPEN_EXISTING, fileFlag, 0)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer func() {
|
|
closeErr := syscall.Close(h)
|
|
if err == nil {
|
|
err = closeErr
|
|
}
|
|
}()
|
|
var patime, pmtime, pbtime *syscall.Filetime
|
|
if !atime.IsZero() {
|
|
t := syscall.NsecToFiletime(atime.UnixNano())
|
|
patime = &t
|
|
}
|
|
if !mtime.IsZero() {
|
|
t := syscall.NsecToFiletime(mtime.UnixNano())
|
|
pmtime = &t
|
|
}
|
|
if !btime.IsZero() {
|
|
t := syscall.NsecToFiletime(btime.UnixNano())
|
|
pbtime = &t
|
|
}
|
|
return syscall.SetFileTime(h, pbtime, patime, pmtime)
|
|
}
|
|
|
|
// setBTime sets the birth time of the file passed in
|
|
func setBTime(name string, btime time.Time) (err error) {
|
|
return setTimes(name, time.Time{}, time.Time{}, btime, false)
|
|
}
|
|
|
|
// lsetBTime changes the birth time of the link passed in
|
|
func lsetBTime(name string, btime time.Time) error {
|
|
return setTimes(name, time.Time{}, time.Time{}, btime, true)
|
|
}
|