This reverts CL 691255.
Reason for revert: SetNamedSecurityInfo sometimes fails when the path contains symbolic links.
Fixes #74864
Change-Id: Iaf1a5692b35d58c523fd513f27bad9a2e7a334cb
Reviewed-on: https://go-review.googlesource.com/c/go/+/702155
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Auto-Submit: Quim Muntal <quimmuntal@gmail.com>
Reviewed-by: Cherry Mui <cherryyz@google.com>
Reviewed-by: Damien Neil <dneil@google.com>
return sh.CopyFile(dst, src, perm, force)
}
- if err := sh.move(src, dst, perm); err == nil {
- if cfg.BuildX {
- sh.ShowCmd("", "mv %s %s", src, dst)
+ // On Windows, always copy the file, so that we respect the NTFS
+ // permissions of the parent folder. https://golang.org/issue/22343.
+ // What matters here is not cfg.Goos (the system we are building
+ // for) but runtime.GOOS (the system we are building on).
+ if runtime.GOOS == "windows" {
+ return sh.CopyFile(dst, src, perm, force)
+ }
+
+ // If the destination directory has the group sticky bit set,
+ // we have to copy the file to retain the correct permissions.
+ // https://golang.org/issue/18878
+ if fi, err := os.Stat(filepath.Dir(dst)); err == nil {
+ if fi.IsDir() && (fi.Mode()&fs.ModeSetgid) != 0 {
+ return sh.CopyFile(dst, src, perm, force)
+ }
+ }
+
+ // The perm argument is meant to be adjusted according to umask,
+ // but we don't know what the umask is.
+ // Create a dummy file to find out.
+ // This avoids build tags and works even on systems like Plan 9
+ // where the file mask computation incorporates other information.
+ mode := perm
+ f, err := os.OpenFile(filepath.Clean(dst)+"-go-tmp-umask", os.O_WRONLY|os.O_CREATE|os.O_EXCL, perm)
+ if err == nil {
+ fi, err := f.Stat()
+ if err == nil {
+ mode = fi.Mode() & 0777
+ }
+ name := f.Name()
+ f.Close()
+ os.Remove(name)
+ }
+
+ if err := os.Chmod(src, mode); err == nil {
+ if err := os.Rename(src, dst); err == nil {
+ if cfg.BuildX {
+ sh.ShowCmd("", "mv %s %s", src, dst)
+ }
+ return nil
}
- return nil
}
return sh.CopyFile(dst, src, perm, force)
+++ /dev/null
-// Copyright 2025 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-//go:build !windows
-
-package work
-
-import (
- "errors"
- "io/fs"
- "os"
- "path/filepath"
-)
-
-// move moves a file from src to dst setting the permissions
-// on the destination file to inherit the permissions from the
-// destination parent directory.
-func (sh *Shell) move(src, dst string, perm fs.FileMode) error {
- // If the destination directory has the group sticky bit set,
- // we have to copy the file to retain the correct permissions.
- // https://golang.org/issue/18878
- if fi, err := os.Stat(filepath.Dir(dst)); err == nil {
- if fi.IsDir() && (fi.Mode()&fs.ModeSetgid) != 0 {
- return errors.ErrUnsupported
- }
- }
- // The perm argument is meant to be adjusted according to umask,
- // but we don't know what the umask is.
- // Create a dummy file to find out.
- // This works even on systems like Plan 9 where the
- // file mask computation incorporates other information.
- mode := perm
- f, err := os.OpenFile(filepath.Clean(dst)+"-go-tmp-umask", os.O_WRONLY|os.O_CREATE|os.O_EXCL, perm)
- if err == nil {
- fi, err := f.Stat()
- if err == nil {
- mode = fi.Mode() & 0777
- }
- name := f.Name()
- f.Close()
- os.Remove(name)
- }
-
- if err := os.Chmod(src, mode); err != nil {
- return err
- }
- return os.Rename(src, dst)
-}
+++ /dev/null
-// Copyright 2025 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package work
-
-import (
- "internal/syscall/windows"
- "io/fs"
- "os"
- "unsafe"
-)
-
-// move moves a file from src to dst, setting the security information
-// on the destination file to inherit the permissions from the
-// destination parent directory.
-func (sh *Shell) move(src, dst string, perm fs.FileMode) (err error) {
- if err := os.Rename(src, dst); err != nil {
- return err
- }
- defer func() {
- if err != nil {
- os.Remove(dst) // clean up if we failed to set the mode or security info
- }
- }()
- if err := os.Chmod(dst, perm); err != nil {
- return err
- }
- // We need to respect the ACL permissions of the destination parent folder.
- // https://go.dev/issue/22343.
- var acl windows.ACL
- if err := windows.InitializeAcl(&acl, uint32(unsafe.Sizeof(acl)), windows.ACL_REVISION); err != nil {
- return err
- }
- secInfo := windows.DACL_SECURITY_INFORMATION | windows.UNPROTECTED_DACL_SECURITY_INFORMATION
- return windows.SetNamedSecurityInfo(dst, windows.SE_FILE_OBJECT, secInfo, nil, nil, &acl, nil)
-}
defer runtime.KeepAlive(sid)
return *(*uint8)(unsafe.Pointer(getSidSubAuthorityCount(sid)))
}
-
-//sys InitializeAcl(acl *ACL, length uint32, revision uint32) (err error) = advapi32.InitializeAcl
-//sys SetNamedSecurityInfo(objectName string, objectType SE_OBJECT_TYPE, securityInformation SECURITY_INFORMATION, owner *syscall.SID, group *syscall.SID, dacl *ACL, sacl *ACL) (ret error) = advapi32.SetNamedSecurityInfoW
// https://learn.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-osversioninfoexa
// https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/wdm/ns-wdm-_osversioninfoexw
const VER_NT_WORKSTATION = 0x0000001
-
-// https://learn.microsoft.com/en-us/windows/win32/api/accctrl/ne-accctrl-se_object_type
-type SE_OBJECT_TYPE uint32
-
-const (
- SE_UNKNOWN_OBJECT_TYPE SE_OBJECT_TYPE = 0
- SE_FILE_OBJECT SE_OBJECT_TYPE = 1
-)
-
-// https://learn.microsoft.com/en-us/windows/win32/secauthz/security-information
-type SECURITY_INFORMATION uint32
-
-const (
- DACL_SECURITY_INFORMATION SECURITY_INFORMATION = 0x00000004
- UNPROTECTED_DACL_SECURITY_INFORMATION SECURITY_INFORMATION = 0x20000000
-)
-
-const ACL_REVISION = 2
procGetSidSubAuthorityCount = modadvapi32.NewProc("GetSidSubAuthorityCount")
procImpersonateLoggedOnUser = modadvapi32.NewProc("ImpersonateLoggedOnUser")
procImpersonateSelf = modadvapi32.NewProc("ImpersonateSelf")
- procInitializeAcl = modadvapi32.NewProc("InitializeAcl")
procIsValidSid = modadvapi32.NewProc("IsValidSid")
procLogonUserW = modadvapi32.NewProc("LogonUserW")
procLookupPrivilegeValueW = modadvapi32.NewProc("LookupPrivilegeValueW")
procOpenThreadToken = modadvapi32.NewProc("OpenThreadToken")
procQueryServiceStatus = modadvapi32.NewProc("QueryServiceStatus")
procRevertToSelf = modadvapi32.NewProc("RevertToSelf")
- procSetNamedSecurityInfoW = modadvapi32.NewProc("SetNamedSecurityInfoW")
procSetTokenInformation = modadvapi32.NewProc("SetTokenInformation")
procProcessPrng = modbcryptprimitives.NewProc("ProcessPrng")
procGetAdaptersAddresses = modiphlpapi.NewProc("GetAdaptersAddresses")
return
}
-func InitializeAcl(acl *ACL, length uint32, revision uint32) (err error) {
- r1, _, e1 := syscall.Syscall(procInitializeAcl.Addr(), 3, uintptr(unsafe.Pointer(acl)), uintptr(length), uintptr(revision))
- if r1 == 0 {
- err = errnoErr(e1)
- }
- return
-}
-
func IsValidSid(sid *syscall.SID) (valid bool) {
r0, _, _ := syscall.Syscall(procIsValidSid.Addr(), 1, uintptr(unsafe.Pointer(sid)), 0, 0)
valid = r0 != 0
return
}
-func SetNamedSecurityInfo(objectName string, objectType SE_OBJECT_TYPE, securityInformation SECURITY_INFORMATION, owner *syscall.SID, group *syscall.SID, dacl *ACL, sacl *ACL) (ret error) {
- var _p0 *uint16
- _p0, ret = syscall.UTF16PtrFromString(objectName)
- if ret != nil {
- return
- }
- return _SetNamedSecurityInfo(_p0, objectType, securityInformation, owner, group, dacl, sacl)
-}
-
-func _SetNamedSecurityInfo(objectName *uint16, objectType SE_OBJECT_TYPE, securityInformation SECURITY_INFORMATION, owner *syscall.SID, group *syscall.SID, dacl *ACL, sacl *ACL) (ret error) {
- r0, _, _ := syscall.Syscall9(procSetNamedSecurityInfoW.Addr(), 7, uintptr(unsafe.Pointer(objectName)), uintptr(objectType), uintptr(securityInformation), uintptr(unsafe.Pointer(owner)), uintptr(unsafe.Pointer(group)), uintptr(unsafe.Pointer(dacl)), uintptr(unsafe.Pointer(sacl)), 0, 0)
- if r0 != 0 {
- ret = syscall.Errno(r0)
- }
- return
-}
-
func SetTokenInformation(tokenHandle syscall.Token, tokenInformationClass uint32, tokenInformation unsafe.Pointer, tokenInformationLength uint32) (err error) {
r1, _, e1 := syscall.Syscall6(procSetTokenInformation.Addr(), 4, uintptr(tokenHandle), uintptr(tokenInformationClass), uintptr(tokenInformation), uintptr(tokenInformationLength), 0, 0)
if r1 == 0 {