aboutsummaryrefslogtreecommitdiff
path: root/src/internal/syscall/windows
diff options
context:
space:
mode:
authorDamien Neil <dneil@google.com>2025-03-19 11:15:06 -0700
committerGopher Robot <gobot@golang.org>2025-03-20 15:12:24 -0700
commit2ffda87f2dce71024f72ccff32cbfe29ee676bf8 (patch)
tree5b57b951657aede28982a20aeeb85d825e19670a /src/internal/syscall/windows
parent686128a9f3f112c2e103622190673656811dee5f (diff)
downloadgo-2ffda87f2dce71024f72ccff32cbfe29ee676bf8.tar.xz
os: add Root.Rename
For #67002 Change-Id: Ifb1042bc5ceaeea64296763319b24634bbcb0bf0 Reviewed-on: https://go-review.googlesource.com/c/go/+/659416 Reviewed-by: Ian Lance Taylor <iant@google.com> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Auto-Submit: Damien Neil <dneil@google.com>
Diffstat (limited to 'src/internal/syscall/windows')
-rw-r--r--src/internal/syscall/windows/at_windows.go74
-rw-r--r--src/internal/syscall/windows/types_windows.go22
2 files changed, 96 insertions, 0 deletions
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
+}