diff options
Diffstat (limited to 'src/internal')
| -rw-r--r-- | src/internal/syscall/unix/asm_darwin.s | 1 | ||||
| -rw-r--r-- | src/internal/syscall/unix/asm_openbsd.s | 2 | ||||
| -rw-r--r-- | src/internal/syscall/unix/at.go | 22 | ||||
| -rw-r--r-- | src/internal/syscall/unix/at_darwin.go | 26 | ||||
| -rw-r--r-- | src/internal/syscall/unix/at_libc.go | 26 | ||||
| -rw-r--r-- | src/internal/syscall/unix/at_openbsd.go | 26 | ||||
| -rw-r--r-- | src/internal/syscall/unix/at_solaris.go | 1 | ||||
| -rw-r--r-- | src/internal/syscall/unix/at_sysnum_dragonfly.go | 1 | ||||
| -rw-r--r-- | src/internal/syscall/unix/at_sysnum_freebsd.go | 1 | ||||
| -rw-r--r-- | src/internal/syscall/unix/at_sysnum_netbsd.go | 1 | ||||
| -rw-r--r-- | src/internal/syscall/unix/at_wasip1.go | 18 | ||||
| -rw-r--r-- | src/internal/syscall/unix/renameat2_sysnum_linux.go | 16 | ||||
| -rw-r--r-- | src/internal/syscall/unix/renameat_sysnum_linux.go | 13 | ||||
| -rw-r--r-- | src/internal/syscall/windows/at_windows.go | 74 | ||||
| -rw-r--r-- | src/internal/syscall/windows/types_windows.go | 22 |
15 files changed, 249 insertions, 1 deletions
diff --git a/src/internal/syscall/unix/asm_darwin.s b/src/internal/syscall/unix/asm_darwin.s index 0f28cd1e39..a72240f512 100644 --- a/src/internal/syscall/unix/asm_darwin.s +++ b/src/internal/syscall/unix/asm_darwin.s @@ -27,3 +27,4 @@ TEXT ·libc_readlinkat_trampoline(SB),NOSPLIT,$0-0; JMP libc_readlinkat(SB) TEXT ·libc_mkdirat_trampoline(SB),NOSPLIT,$0-0; JMP libc_mkdirat(SB) TEXT ·libc_fchmodat_trampoline(SB),NOSPLIT,$0-0; JMP libc_fchmodat(SB) TEXT ·libc_fchownat_trampoline(SB),NOSPLIT,$0-0; JMP libc_fchownat(SB) +TEXT ·libc_renameat_trampoline(SB),NOSPLIT,$0-0; JMP libc_renameat(SB) diff --git a/src/internal/syscall/unix/asm_openbsd.s b/src/internal/syscall/unix/asm_openbsd.s index b804a52714..2b88b6988c 100644 --- a/src/internal/syscall/unix/asm_openbsd.s +++ b/src/internal/syscall/unix/asm_openbsd.s @@ -18,3 +18,5 @@ TEXT ·libc_fchmodat_trampoline(SB),NOSPLIT,$0-0 JMP libc_fchmodat(SB) TEXT ·libc_fchownat_trampoline(SB),NOSPLIT,$0-0 JMP libc_fchownat(SB) +TEXT ·libc_renameat_trampoline(SB),NOSPLIT,$0-0 + JMP libc_renameat(SB) diff --git a/src/internal/syscall/unix/at.go b/src/internal/syscall/unix/at.go index 794f8ace14..be7920c115 100644 --- a/src/internal/syscall/unix/at.go +++ b/src/internal/syscall/unix/at.go @@ -114,3 +114,25 @@ func Fchownat(dirfd int, path string, uid, gid int, flags int) error { } return nil } + +func Renameat(olddirfd int, oldpath string, newdirfd int, newpath string) error { + oldp, err := syscall.BytePtrFromString(oldpath) + if err != nil { + return err + } + newp, err := syscall.BytePtrFromString(newpath) + if err != nil { + return err + } + _, _, errno := syscall.Syscall6(renameatTrap, + uintptr(olddirfd), + uintptr(unsafe.Pointer(oldp)), + uintptr(newdirfd), + uintptr(unsafe.Pointer(newp)), + 0, + 0) + if errno != 0 { + return errno + } + return nil +} diff --git a/src/internal/syscall/unix/at_darwin.go b/src/internal/syscall/unix/at_darwin.go index 75d7b45569..4f39b76ad1 100644 --- a/src/internal/syscall/unix/at_darwin.go +++ b/src/internal/syscall/unix/at_darwin.go @@ -102,3 +102,29 @@ func Fchownat(dirfd int, path string, uid, gid int, flags int) error { } return nil } + +func libc_renameat_trampoline() + +//go:cgo_import_dynamic libc_renameat renameat "/usr/lib/libSystem.B.dylib" + +func Renameat(olddirfd int, oldpath string, newdirfd int, newpath string) error { + oldp, err := syscall.BytePtrFromString(oldpath) + if err != nil { + return err + } + newp, err := syscall.BytePtrFromString(newpath) + if err != nil { + return err + } + _, _, errno := syscall_syscall6(abi.FuncPCABI0(libc_renameat_trampoline), + uintptr(olddirfd), + uintptr(unsafe.Pointer(oldp)), + uintptr(newdirfd), + uintptr(unsafe.Pointer(newp)), + 0, + 0) + if errno != 0 { + return errno + } + return nil +} diff --git a/src/internal/syscall/unix/at_libc.go b/src/internal/syscall/unix/at_libc.go index d47f69db6f..36a9f22b2a 100644 --- a/src/internal/syscall/unix/at_libc.go +++ b/src/internal/syscall/unix/at_libc.go @@ -18,6 +18,7 @@ import ( //go:linkname procMkdirat libc_mkdirat //go:linkname procFchmodat libc_fchmodat //go:linkname procFchownat libc_fchownat +//go:linkname procRenameat libc_renameat var ( procFstatat, @@ -26,7 +27,8 @@ var ( procReadlinkat, procMkdirat, procFchmodat, - procFchownat uintptr + procFchownat, + procRenameat uintptr ) func Unlinkat(dirfd int, path string, flags int) error { @@ -160,3 +162,25 @@ func Fchownat(dirfd int, path string, uid, gid int, flags int) error { } return nil } + +func Renameat(olddirfd int, oldpath string, newdirfd int, newpath string) error { + oldp, err := syscall.BytePtrFromString(oldpath) + if err != nil { + return err + } + newp, err := syscall.BytePtrFromString(newpath) + if err != nil { + return err + } + _, _, errno := syscall6(uintptr(unsafe.Pointer(&procRenameat)), 4, + uintptr(olddirfd), + uintptr(unsafe.Pointer(oldp)), + uintptr(newdirfd), + uintptr(unsafe.Pointer(newp)), + 0, + 0) + if errno != 0 { + return errno + } + return nil +} diff --git a/src/internal/syscall/unix/at_openbsd.go b/src/internal/syscall/unix/at_openbsd.go index 22c959b0c7..bd56aac70d 100644 --- a/src/internal/syscall/unix/at_openbsd.go +++ b/src/internal/syscall/unix/at_openbsd.go @@ -93,3 +93,29 @@ func Fchownat(dirfd int, path string, uid, gid int, flags int) error { } return nil } + +//go:cgo_import_dynamic libc_renameat renameat "libc.so" + +func libc_renameat_trampoline() + +func Renameat(olddirfd int, oldpath string, newdirfd int, newpath string) error { + oldp, err := syscall.BytePtrFromString(oldpath) + if err != nil { + return err + } + newp, err := syscall.BytePtrFromString(newpath) + if err != nil { + return err + } + _, _, errno := syscall_syscall6(abi.FuncPCABI0(libc_renameat_trampoline), + uintptr(olddirfd), + uintptr(unsafe.Pointer(oldp)), + uintptr(newdirfd), + uintptr(unsafe.Pointer(newp)), + 0, + 0) + if errno != 0 { + return errno + } + return nil +} diff --git a/src/internal/syscall/unix/at_solaris.go b/src/internal/syscall/unix/at_solaris.go index f84e8e35da..1241827cff 100644 --- a/src/internal/syscall/unix/at_solaris.go +++ b/src/internal/syscall/unix/at_solaris.go @@ -17,6 +17,7 @@ func rawSyscall6(trap, nargs, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, e //go:cgo_import_dynamic libc_fchownat fchownat "libc.so" //go:cgo_import_dynamic libc_fstatat fstatat "libc.so" //go:cgo_import_dynamic libc_openat openat "libc.so" +//go:cgo_import_dynamic libc_renameat renameat "libc.so" //go:cgo_import_dynamic libc_unlinkat unlinkat "libc.so" //go:cgo_import_dynamic libc_readlinkat readlinkat "libc.so" //go:cgo_import_dynamic libc_mkdirat mkdirat "libc.so" diff --git a/src/internal/syscall/unix/at_sysnum_dragonfly.go b/src/internal/syscall/unix/at_sysnum_dragonfly.go index 1e89e97f38..f4418776cd 100644 --- a/src/internal/syscall/unix/at_sysnum_dragonfly.go +++ b/src/internal/syscall/unix/at_sysnum_dragonfly.go @@ -14,6 +14,7 @@ const ( mkdiratTrap uintptr = syscall.SYS_MKDIRAT fchmodatTrap uintptr = syscall.SYS_FCHMODAT fchownatTrap uintptr = syscall.SYS_FCHOWNAT + renameatTrap uintptr = syscall.SYS_RENAMEAT AT_EACCESS = 0x4 AT_FDCWD = 0xfffafdcd diff --git a/src/internal/syscall/unix/at_sysnum_freebsd.go b/src/internal/syscall/unix/at_sysnum_freebsd.go index 59a8c2ce5a..d1bec15343 100644 --- a/src/internal/syscall/unix/at_sysnum_freebsd.go +++ b/src/internal/syscall/unix/at_sysnum_freebsd.go @@ -21,4 +21,5 @@ const ( mkdiratTrap uintptr = syscall.SYS_MKDIRAT fchmodatTrap uintptr = syscall.SYS_FCHMODAT fchownatTrap uintptr = syscall.SYS_FCHOWNAT + renameatTrap uintptr = syscall.SYS_RENAMEAT ) diff --git a/src/internal/syscall/unix/at_sysnum_netbsd.go b/src/internal/syscall/unix/at_sysnum_netbsd.go index bb946b6581..db42be58b7 100644 --- a/src/internal/syscall/unix/at_sysnum_netbsd.go +++ b/src/internal/syscall/unix/at_sysnum_netbsd.go @@ -14,6 +14,7 @@ const ( mkdiratTrap uintptr = syscall.SYS_MKDIRAT fchmodatTrap uintptr = syscall.SYS_FCHMODAT fchownatTrap uintptr = syscall.SYS_FCHOWNAT + renameatTrap uintptr = syscall.SYS_RENAMEAT ) const ( diff --git a/src/internal/syscall/unix/at_wasip1.go b/src/internal/syscall/unix/at_wasip1.go index 3fdc95436c..2bd55ca0e7 100644 --- a/src/internal/syscall/unix/at_wasip1.go +++ b/src/internal/syscall/unix/at_wasip1.go @@ -111,6 +111,24 @@ func Fchownat(dirfd int, path string, uid, gid int, flags int) error { return syscall.ENOSYS } +//go:wasmimport wasi_snapshot_preview1 path_rename +//go:noescape +func path_rename(oldFd int32, oldPath *byte, oldPathLen size, newFd int32, newPath *byte, newPathLen size) syscall.Errno + +func Renameat(olddirfd int, oldpath string, newdirfd int, newpath string) error { + if oldpath == "" || newpath == "" { + return syscall.EINVAL + } + return errnoErr(path_rename( + int32(olddirfd), + unsafe.StringData(oldpath), + size(len(oldpath)), + int32(newdirfd), + unsafe.StringData(newpath), + size(len(newpath)), + )) +} + //go:wasmimport wasi_snapshot_preview1 path_create_directory //go:noescape func path_create_directory(fd int32, path *byte, pathLen size) syscall.Errno diff --git a/src/internal/syscall/unix/renameat2_sysnum_linux.go b/src/internal/syscall/unix/renameat2_sysnum_linux.go new file mode 100644 index 0000000000..e41a65db79 --- /dev/null +++ b/src/internal/syscall/unix/renameat2_sysnum_linux.go @@ -0,0 +1,16 @@ +// 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 linux && (loong64 || riscv64) + +package unix + +import "syscall" + +const ( + // loong64 and riscv64 only have renameat2. + // renameat2 has an extra flags parameter. + // When called with a 0 flags it is identical to renameat. + renameatTrap uintptr = syscall.SYS_RENAMEAT2 +) diff --git a/src/internal/syscall/unix/renameat_sysnum_linux.go b/src/internal/syscall/unix/renameat_sysnum_linux.go new file mode 100644 index 0000000000..d3663ad1dc --- /dev/null +++ b/src/internal/syscall/unix/renameat_sysnum_linux.go @@ -0,0 +1,13 @@ +// 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 linux && !(loong64 || riscv64) + +package unix + +import "syscall" + +const ( + renameatTrap uintptr = syscall.SYS_RENAMEAT +) diff --git a/src/internal/syscall/windows/at_windows.go b/src/internal/syscall/windows/at_windows.go index 19bcc0dbac..edd2e42a88 100644 --- a/src/internal/syscall/windows/at_windows.go +++ b/src/internal/syscall/windows/at_windows.go @@ -254,3 +254,77 @@ func Deleteat(dirfd syscall.Handle, name string) error { } return err } + +func Renameat(olddirfd syscall.Handle, oldpath string, newdirfd syscall.Handle, newpath string) error { + objAttrs := &OBJECT_ATTRIBUTES{} + if err := objAttrs.init(olddirfd, oldpath); err != nil { + return err + } + var h syscall.Handle + err := NtOpenFile( + &h, + SYNCHRONIZE|DELETE, + objAttrs, + &IO_STATUS_BLOCK{}, + FILE_SHARE_DELETE|FILE_SHARE_READ|FILE_SHARE_WRITE, + FILE_OPEN_REPARSE_POINT|FILE_OPEN_FOR_BACKUP_INTENT|FILE_SYNCHRONOUS_IO_NONALERT, + ) + if err != nil { + return ntCreateFileError(err, 0) + } + defer syscall.CloseHandle(h) + + renameInfoEx := FILE_RENAME_INFORMATION_EX{ + Flags: FILE_RENAME_REPLACE_IF_EXISTS | + FILE_RENAME_POSIX_SEMANTICS, + RootDirectory: newdirfd, + } + p16, err := syscall.UTF16FromString(newpath) + if err != nil { + return err + } + if len(p16) > len(renameInfoEx.FileName) { + return syscall.EINVAL + } + copy(renameInfoEx.FileName[:], p16) + renameInfoEx.FileNameLength = uint32((len(p16) - 1) * 2) + + const ( + FileRenameInformation = 10 + FileRenameInformationEx = 65 + ) + err = NtSetInformationFile( + h, + &IO_STATUS_BLOCK{}, + uintptr(unsafe.Pointer(&renameInfoEx)), + uint32(unsafe.Sizeof(FILE_RENAME_INFORMATION_EX{})), + FileRenameInformationEx, + ) + if err == nil { + return nil + } + + // If the prior rename failed, the filesystem might not support + // POSIX semantics (for example, FAT), or might not have implemented + // FILE_RENAME_INFORMATION_EX. + // + // Try again. + renameInfo := FILE_RENAME_INFORMATION{ + ReplaceIfExists: true, + RootDirectory: newdirfd, + } + copy(renameInfo.FileName[:], p16) + renameInfo.FileNameLength = renameInfoEx.FileNameLength + + err = NtSetInformationFile( + h, + &IO_STATUS_BLOCK{}, + uintptr(unsafe.Pointer(&renameInfo)), + uint32(unsafe.Sizeof(FILE_RENAME_INFORMATION{})), + FileRenameInformation, + ) + if st, ok := err.(NTStatus); ok { + return st.Errno() + } + return err +} diff --git a/src/internal/syscall/windows/types_windows.go b/src/internal/syscall/windows/types_windows.go index 6ae37afff8..718a4b863a 100644 --- a/src/internal/syscall/windows/types_windows.go +++ b/src/internal/syscall/windows/types_windows.go @@ -216,3 +216,25 @@ const ( FILE_DISPOSITION_ON_CLOSE = 0x00000008 FILE_DISPOSITION_IGNORE_READONLY_ATTRIBUTE = 0x00000010 ) + +// Flags for FILE_RENAME_INFORMATION_EX. +const ( + FILE_RENAME_REPLACE_IF_EXISTS = 0x00000001 + FILE_RENAME_POSIX_SEMANTICS = 0x00000002 +) + +// https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/ntifs/ns-ntifs-_file_rename_information +type FILE_RENAME_INFORMATION struct { + ReplaceIfExists bool + RootDirectory syscall.Handle + FileNameLength uint32 + FileName [syscall.MAX_PATH]uint16 +} + +// https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/ntifs/ns-ntifs-_file_rename_information +type FILE_RENAME_INFORMATION_EX struct { + Flags uint32 + RootDirectory syscall.Handle + FileNameLength uint32 + FileName [syscall.MAX_PATH]uint16 +} |
