diff options
| author | Damien Neil <dneil@google.com> | 2025-03-20 12:41:21 -0700 |
|---|---|---|
| committer | Gopher Robot <gobot@golang.org> | 2025-03-24 07:53:38 -0700 |
| commit | d2d1fd68b6299d4645298e6d70fe8e8cfd98001a (patch) | |
| tree | 8108bd9125f95c6a66e5c2c30db5614a6c939ff8 /src/internal | |
| parent | 4ae6ab2bdfe3ebe8340d0d49fd2bb73f1a3e19ff (diff) | |
| download | go-d2d1fd68b6299d4645298e6d70fe8e8cfd98001a.tar.xz | |
os: add Root.Link
For #67002
Change-Id: I223f3f2dbc8b02726f4ce5a017c628c4a20f109a
Reviewed-on: https://go-review.googlesource.com/c/go/+/659757
Reviewed-by: Quim Muntal <quimmuntal@gmail.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Auto-Submit: Damien Neil <dneil@google.com>
Reviewed-by: Ian Lance Taylor <iant@google.com>
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_aix.go | 1 | ||||
| -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_linux.go | 1 | ||||
| -rw-r--r-- | src/internal/syscall/unix/at_sysnum_netbsd.go | 1 | ||||
| -rw-r--r-- | src/internal/syscall/unix/at_wasip1.go | 19 | ||||
| -rw-r--r-- | src/internal/syscall/windows/at_windows.go | 48 | ||||
| -rw-r--r-- | src/internal/syscall/windows/types_windows.go | 8 |
15 files changed, 183 insertions, 1 deletions
diff --git a/src/internal/syscall/unix/asm_darwin.s b/src/internal/syscall/unix/asm_darwin.s index a72240f512..79d384c941 100644 --- a/src/internal/syscall/unix/asm_darwin.s +++ b/src/internal/syscall/unix/asm_darwin.s @@ -28,3 +28,4 @@ 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) +TEXT ·libc_linkat_trampoline(SB),NOSPLIT,$0-0; JMP libc_linkat(SB) diff --git a/src/internal/syscall/unix/asm_openbsd.s b/src/internal/syscall/unix/asm_openbsd.s index 2b88b6988c..481dd7d700 100644 --- a/src/internal/syscall/unix/asm_openbsd.s +++ b/src/internal/syscall/unix/asm_openbsd.s @@ -20,3 +20,5 @@ TEXT ·libc_fchownat_trampoline(SB),NOSPLIT,$0-0 JMP libc_fchownat(SB) TEXT ·libc_renameat_trampoline(SB),NOSPLIT,$0-0 JMP libc_renameat(SB) +TEXT ·libc_linkat_trampoline(SB),NOSPLIT,$0-0 + JMP libc_linkat(SB) diff --git a/src/internal/syscall/unix/at.go b/src/internal/syscall/unix/at.go index be7920c115..4549a07f8c 100644 --- a/src/internal/syscall/unix/at.go +++ b/src/internal/syscall/unix/at.go @@ -136,3 +136,25 @@ func Renameat(olddirfd int, oldpath string, newdirfd int, newpath string) error } return nil } + +func Linkat(olddirfd int, oldpath string, newdirfd int, newpath string, flag int) error { + oldp, err := syscall.BytePtrFromString(oldpath) + if err != nil { + return err + } + newp, err := syscall.BytePtrFromString(newpath) + if err != nil { + return err + } + _, _, errno := syscall.Syscall6(linkatTrap, + uintptr(olddirfd), + uintptr(unsafe.Pointer(oldp)), + uintptr(newdirfd), + uintptr(unsafe.Pointer(newp)), + uintptr(flag), + 0) + if errno != 0 { + return errno + } + return nil +} diff --git a/src/internal/syscall/unix/at_aix.go b/src/internal/syscall/unix/at_aix.go index d277cd332f..573554927e 100644 --- a/src/internal/syscall/unix/at_aix.go +++ b/src/internal/syscall/unix/at_aix.go @@ -7,6 +7,7 @@ package unix //go:cgo_import_dynamic libc_fchmodat fchmodat "libc.a/shr_64.o" //go:cgo_import_dynamic libc_fchownat fchownat "libc.a/shr_64.o" //go:cgo_import_dynamic libc_fstatat fstatat "libc.a/shr_64.o" +//go:cgo_import_dynamic libc_linkat linkat "libc.a/shr_64.o" //go:cgo_import_dynamic libc_openat openat "libc.a/shr_64.o" //go:cgo_import_dynamic libc_renameat renameat "libc.a/shr_64.o" //go:cgo_import_dynamic libc_unlinkat unlinkat "libc.a/shr_64.o" diff --git a/src/internal/syscall/unix/at_darwin.go b/src/internal/syscall/unix/at_darwin.go index 4f39b76ad1..61437672ee 100644 --- a/src/internal/syscall/unix/at_darwin.go +++ b/src/internal/syscall/unix/at_darwin.go @@ -128,3 +128,29 @@ func Renameat(olddirfd int, oldpath string, newdirfd int, newpath string) error } return nil } + +func libc_linkat_trampoline() + +//go:cgo_import_dynamic libc_linkat linkat "/usr/lib/libSystem.B.dylib" + +func Linkat(olddirfd int, oldpath string, newdirfd int, newpath string, flag int) 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_linkat_trampoline), + uintptr(olddirfd), + uintptr(unsafe.Pointer(oldp)), + uintptr(newdirfd), + uintptr(unsafe.Pointer(newp)), + uintptr(flag), + 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 36a9f22b2a..b32d3bba39 100644 --- a/src/internal/syscall/unix/at_libc.go +++ b/src/internal/syscall/unix/at_libc.go @@ -19,6 +19,7 @@ import ( //go:linkname procFchmodat libc_fchmodat //go:linkname procFchownat libc_fchownat //go:linkname procRenameat libc_renameat +//go:linkname procLinkat libc_linkat var ( procFstatat, @@ -28,7 +29,8 @@ var ( procMkdirat, procFchmodat, procFchownat, - procRenameat uintptr + procRenameat, + procLinkat uintptr ) func Unlinkat(dirfd int, path string, flags int) error { @@ -184,3 +186,25 @@ func Renameat(olddirfd int, oldpath string, newdirfd int, newpath string) error } return nil } + +func Linkat(olddirfd int, oldpath string, newdirfd int, newpath string, flag int) 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(&procLinkat)), 5, + uintptr(olddirfd), + uintptr(unsafe.Pointer(oldp)), + uintptr(newdirfd), + uintptr(unsafe.Pointer(newp)), + uintptr(flag), + 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 bd56aac70d..2a433930f3 100644 --- a/src/internal/syscall/unix/at_openbsd.go +++ b/src/internal/syscall/unix/at_openbsd.go @@ -119,3 +119,29 @@ func Renameat(olddirfd int, oldpath string, newdirfd int, newpath string) error } return nil } + +func libc_linkat_trampoline() + +//go:cgo_import_dynamic libc_linkat linkat "libc.so" + +func Linkat(olddirfd int, oldpath string, newdirfd int, newpath string, flag int) 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_linkat_trampoline), + uintptr(olddirfd), + uintptr(unsafe.Pointer(oldp)), + uintptr(newdirfd), + uintptr(unsafe.Pointer(newp)), + uintptr(flag), + 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 1241827cff..abfda15688 100644 --- a/src/internal/syscall/unix/at_solaris.go +++ b/src/internal/syscall/unix/at_solaris.go @@ -16,6 +16,7 @@ func rawSyscall6(trap, nargs, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, e //go:cgo_import_dynamic libc_fchmodat fchmodat "libc.so" //go:cgo_import_dynamic libc_fchownat fchownat "libc.so" //go:cgo_import_dynamic libc_fstatat fstatat "libc.so" +//go:cgo_import_dynamic libc_linkat linkat "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" diff --git a/src/internal/syscall/unix/at_sysnum_dragonfly.go b/src/internal/syscall/unix/at_sysnum_dragonfly.go index f4418776cd..3ba2c54152 100644 --- a/src/internal/syscall/unix/at_sysnum_dragonfly.go +++ b/src/internal/syscall/unix/at_sysnum_dragonfly.go @@ -15,6 +15,7 @@ const ( fchmodatTrap uintptr = syscall.SYS_FCHMODAT fchownatTrap uintptr = syscall.SYS_FCHOWNAT renameatTrap uintptr = syscall.SYS_RENAMEAT + linkatTrap uintptr = syscall.SYS_LINKAT 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 d1bec15343..032b8b5276 100644 --- a/src/internal/syscall/unix/at_sysnum_freebsd.go +++ b/src/internal/syscall/unix/at_sysnum_freebsd.go @@ -22,4 +22,5 @@ const ( fchmodatTrap uintptr = syscall.SYS_FCHMODAT fchownatTrap uintptr = syscall.SYS_FCHOWNAT renameatTrap uintptr = syscall.SYS_RENAMEAT + linkatTrap uintptr = syscall.SYS_LINKAT ) diff --git a/src/internal/syscall/unix/at_sysnum_linux.go b/src/internal/syscall/unix/at_sysnum_linux.go index 35cc4307e9..6b8bebff2a 100644 --- a/src/internal/syscall/unix/at_sysnum_linux.go +++ b/src/internal/syscall/unix/at_sysnum_linux.go @@ -13,6 +13,7 @@ const ( mkdiratTrap uintptr = syscall.SYS_MKDIRAT fchmodatTrap uintptr = syscall.SYS_FCHMODAT fchownatTrap uintptr = syscall.SYS_FCHOWNAT + linkatTrap uintptr = syscall.SYS_LINKAT ) const ( diff --git a/src/internal/syscall/unix/at_sysnum_netbsd.go b/src/internal/syscall/unix/at_sysnum_netbsd.go index db42be58b7..01e10ddd59 100644 --- a/src/internal/syscall/unix/at_sysnum_netbsd.go +++ b/src/internal/syscall/unix/at_sysnum_netbsd.go @@ -15,6 +15,7 @@ const ( fchmodatTrap uintptr = syscall.SYS_FCHMODAT fchownatTrap uintptr = syscall.SYS_FCHOWNAT renameatTrap uintptr = syscall.SYS_RENAMEAT + linkatTrap uintptr = syscall.SYS_LINKAT ) const ( diff --git a/src/internal/syscall/unix/at_wasip1.go b/src/internal/syscall/unix/at_wasip1.go index 2bd55ca0e7..72537caf1e 100644 --- a/src/internal/syscall/unix/at_wasip1.go +++ b/src/internal/syscall/unix/at_wasip1.go @@ -129,6 +129,25 @@ func Renameat(olddirfd int, oldpath string, newdirfd int, newpath string) error )) } +//go:wasmimport wasi_snapshot_preview1 path_link +//go:noescape +func path_link(oldFd int32, oldFlags uint32, oldPath *byte, oldPathLen size, newFd int32, newPath *byte, newPathLen size) syscall.Errno + +func Linkat(olddirfd int, oldpath string, newdirfd int, newpath string, flag int) error { + if oldpath == "" || newpath == "" { + return syscall.EINVAL + } + return errnoErr(path_link( + int32(olddirfd), + 0, + 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/windows/at_windows.go b/src/internal/syscall/windows/at_windows.go index 311e143b9b..4b939d46ab 100644 --- a/src/internal/syscall/windows/at_windows.go +++ b/src/internal/syscall/windows/at_windows.go @@ -328,3 +328,51 @@ func Renameat(olddirfd syscall.Handle, oldpath string, newdirfd syscall.Handle, } return err } + +func Linkat(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|FILE_WRITE_ATTRIBUTES, + 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) + + linkInfo := FILE_LINK_INFORMATION{ + RootDirectory: newdirfd, + } + p16, err := syscall.UTF16FromString(newpath) + if err != nil { + return err + } + if len(p16) > len(linkInfo.FileName) { + return syscall.EINVAL + } + copy(linkInfo.FileName[:], p16) + linkInfo.FileNameLength = uint32((len(p16) - 1) * 2) + + const ( + FileLinkInformation = 11 + ) + err = NtSetInformationFile( + h, + &IO_STATUS_BLOCK{}, + uintptr(unsafe.Pointer(&linkInfo)), + uint32(unsafe.Sizeof(FILE_LINK_INFORMATION{})), + FileLinkInformation, + ) + 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 718a4b863a..adc8b00bd8 100644 --- a/src/internal/syscall/windows/types_windows.go +++ b/src/internal/syscall/windows/types_windows.go @@ -238,3 +238,11 @@ type FILE_RENAME_INFORMATION_EX struct { FileNameLength uint32 FileName [syscall.MAX_PATH]uint16 } + +// https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/ntifs/ns-ntifs-_file_link_information +type FILE_LINK_INFORMATION struct { + ReplaceIfExists bool + RootDirectory syscall.Handle + FileNameLength uint32 + FileName [syscall.MAX_PATH]uint16 +} |
