diff options
Diffstat (limited to 'src/internal/syscall/windows')
| -rw-r--r-- | src/internal/syscall/windows/at_windows.go | 70 | ||||
| -rw-r--r-- | src/internal/syscall/windows/syscall_windows.go | 4 | ||||
| -rw-r--r-- | src/internal/syscall/windows/types_windows.go | 20 | ||||
| -rw-r--r-- | src/internal/syscall/windows/zsyscall_windows.go | 18 |
4 files changed, 112 insertions, 0 deletions
diff --git a/src/internal/syscall/windows/at_windows.go b/src/internal/syscall/windows/at_windows.go index af8167dd06..72780139a0 100644 --- a/src/internal/syscall/windows/at_windows.go +++ b/src/internal/syscall/windows/at_windows.go @@ -6,6 +6,7 @@ package windows import ( "syscall" + "unsafe" ) // Openat flags not supported by syscall.Open. @@ -171,3 +172,72 @@ func Mkdirat(dirfd syscall.Handle, name string, mode uint32) error { syscall.CloseHandle(h) return nil } + +func Deleteat(dirfd syscall.Handle, name string) error { + objAttrs := &OBJECT_ATTRIBUTES{} + if err := objAttrs.init(dirfd, name); err != nil { + return err + } + var h syscall.Handle + err := NtOpenFile( + &h, + DELETE, + objAttrs, + &IO_STATUS_BLOCK{}, + FILE_SHARE_DELETE|FILE_SHARE_READ|FILE_SHARE_WRITE, + FILE_OPEN_REPARSE_POINT|FILE_OPEN_FOR_BACKUP_INTENT, + ) + if err != nil { + return ntCreateFileError(err, 0) + } + defer syscall.CloseHandle(h) + + const ( + FileDispositionInformation = 13 + FileDispositionInformationEx = 64 + ) + + // First, attempt to delete the file using POSIX semantics + // (which permit a file to be deleted while it is still open). + // This matches the behavior of DeleteFileW. + err = NtSetInformationFile( + h, + &IO_STATUS_BLOCK{}, + uintptr(unsafe.Pointer(&FILE_DISPOSITION_INFORMATION_EX{ + Flags: FILE_DISPOSITION_DELETE | + FILE_DISPOSITION_FORCE_IMAGE_SECTION_CHECK | + FILE_DISPOSITION_POSIX_SEMANTICS | + // This differs from DeleteFileW, but matches os.Remove's + // behavior on Unix platforms of permitting deletion of + // read-only files. + FILE_DISPOSITION_IGNORE_READONLY_ATTRIBUTE, + })), + uint32(unsafe.Sizeof(FILE_DISPOSITION_INFORMATION_EX{})), + FileDispositionInformationEx, + ) + switch err { + case nil: + return nil + case STATUS_CANNOT_DELETE, STATUS_DIRECTORY_NOT_EMPTY: + return err.(NTStatus).Errno() + } + + // If the prior deletion failed, the filesystem either doesn't support + // POSIX semantics (for example, FAT), or hasn't implemented + // FILE_DISPOSITION_INFORMATION_EX. + // + // Try again. + err = NtSetInformationFile( + h, + &IO_STATUS_BLOCK{}, + uintptr(unsafe.Pointer(&FILE_DISPOSITION_INFORMATION{ + DeleteFile: true, + })), + uint32(unsafe.Sizeof(FILE_DISPOSITION_INFORMATION{})), + FileDispositionInformation, + ) + if st, ok := err.(NTStatus); ok { + return st.Errno() + } + return err +} diff --git a/src/internal/syscall/windows/syscall_windows.go b/src/internal/syscall/windows/syscall_windows.go index 924f4951e7..f6fbf199bf 100644 --- a/src/internal/syscall/windows/syscall_windows.go +++ b/src/internal/syscall/windows/syscall_windows.go @@ -523,10 +523,14 @@ func (s NTStatus) Error() string { // If this list starts getting long, we should consider generating the full set. const ( STATUS_FILE_IS_A_DIRECTORY NTStatus = 0xC00000BA + STATUS_DIRECTORY_NOT_EMPTY NTStatus = 0xC0000101 STATUS_NOT_A_DIRECTORY NTStatus = 0xC0000103 + STATUS_CANNOT_DELETE NTStatus = 0xC0000121 STATUS_REPARSE_POINT_ENCOUNTERED NTStatus = 0xC000050B ) // NT Native APIs //sys NtCreateFile(handle *syscall.Handle, access uint32, oa *OBJECT_ATTRIBUTES, iosb *IO_STATUS_BLOCK, allocationSize *int64, attributes uint32, share uint32, disposition uint32, options uint32, eabuffer uintptr, ealength uint32) (ntstatus error) = ntdll.NtCreateFile +//sys NtOpenFile(handle *syscall.Handle, access uint32, oa *OBJECT_ATTRIBUTES, iosb *IO_STATUS_BLOCK, share uint32, options uint32) (ntstatus error) = ntdll.NtOpenFile //sys rtlNtStatusToDosErrorNoTeb(ntstatus NTStatus) (ret syscall.Errno) = ntdll.RtlNtStatusToDosErrorNoTeb +//sys NtSetInformationFile(handle syscall.Handle, iosb *IO_STATUS_BLOCK, inBuffer uintptr, inBufferLen uint32, class uint32) (ntstatus error) = ntdll.NtSetInformationFile diff --git a/src/internal/syscall/windows/types_windows.go b/src/internal/syscall/windows/types_windows.go index 514feafae4..6ae37afff8 100644 --- a/src/internal/syscall/windows/types_windows.go +++ b/src/internal/syscall/windows/types_windows.go @@ -196,3 +196,23 @@ const ( FILE_OPEN_NO_RECALL = 0x00400000 FILE_OPEN_FOR_FREE_SPACE_QUERY = 0x00800000 ) + +// https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/ntddk/ns-ntddk-_file_disposition_information +type FILE_DISPOSITION_INFORMATION struct { + DeleteFile bool +} + +// https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/ntddk/ns-ntddk-_file_disposition_information_ex +type FILE_DISPOSITION_INFORMATION_EX struct { + Flags uint32 +} + +// https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/ntddk/ns-ntddk-_file_disposition_information_ex +const ( + FILE_DISPOSITION_DO_NOT_DELETE = 0x00000000 + FILE_DISPOSITION_DELETE = 0x00000001 + FILE_DISPOSITION_POSIX_SEMANTICS = 0x00000002 + FILE_DISPOSITION_FORCE_IMAGE_SECTION_CHECK = 0x00000004 + FILE_DISPOSITION_ON_CLOSE = 0x00000008 + FILE_DISPOSITION_IGNORE_READONLY_ATTRIBUTE = 0x00000010 +) diff --git a/src/internal/syscall/windows/zsyscall_windows.go b/src/internal/syscall/windows/zsyscall_windows.go index c81bc399ff..6a6ea7bdc0 100644 --- a/src/internal/syscall/windows/zsyscall_windows.go +++ b/src/internal/syscall/windows/zsyscall_windows.go @@ -93,6 +93,8 @@ var ( procNetUserDel = modnetapi32.NewProc("NetUserDel") procNetUserGetLocalGroups = modnetapi32.NewProc("NetUserGetLocalGroups") procNtCreateFile = modntdll.NewProc("NtCreateFile") + procNtOpenFile = modntdll.NewProc("NtOpenFile") + procNtSetInformationFile = modntdll.NewProc("NtSetInformationFile") procRtlGetVersion = modntdll.NewProc("RtlGetVersion") procRtlNtStatusToDosErrorNoTeb = modntdll.NewProc("RtlNtStatusToDosErrorNoTeb") procGetProcessMemoryInfo = modpsapi.NewProc("GetProcessMemoryInfo") @@ -477,6 +479,22 @@ func NtCreateFile(handle *syscall.Handle, access uint32, oa *OBJECT_ATTRIBUTES, return } +func NtOpenFile(handle *syscall.Handle, access uint32, oa *OBJECT_ATTRIBUTES, iosb *IO_STATUS_BLOCK, share uint32, options uint32) (ntstatus error) { + r0, _, _ := syscall.Syscall6(procNtOpenFile.Addr(), 6, uintptr(unsafe.Pointer(handle)), uintptr(access), uintptr(unsafe.Pointer(oa)), uintptr(unsafe.Pointer(iosb)), uintptr(share), uintptr(options)) + if r0 != 0 { + ntstatus = NTStatus(r0) + } + return +} + +func NtSetInformationFile(handle syscall.Handle, iosb *IO_STATUS_BLOCK, inBuffer uintptr, inBufferLen uint32, class uint32) (ntstatus error) { + r0, _, _ := syscall.Syscall6(procNtSetInformationFile.Addr(), 5, uintptr(handle), uintptr(unsafe.Pointer(iosb)), uintptr(inBuffer), uintptr(inBufferLen), uintptr(class), 0) + if r0 != 0 { + ntstatus = NTStatus(r0) + } + return +} + func rtlGetVersion(info *_OSVERSIONINFOW) { syscall.Syscall(procRtlGetVersion.Addr(), 1, uintptr(unsafe.Pointer(info)), 0, 0) return |
