diff options
| author | Damien Neil <dneil@google.com> | 2025-03-19 11:15:06 -0700 |
|---|---|---|
| committer | Gopher Robot <gobot@golang.org> | 2025-03-20 15:12:24 -0700 |
| commit | 2ffda87f2dce71024f72ccff32cbfe29ee676bf8 (patch) | |
| tree | 5b57b951657aede28982a20aeeb85d825e19670a /src/internal/syscall/windows | |
| parent | 686128a9f3f112c2e103622190673656811dee5f (diff) | |
| download | go-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.go | 74 | ||||
| -rw-r--r-- | src/internal/syscall/windows/types_windows.go | 22 |
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 +} |
