зеркало из https://github.com/golang/sys.git
windows: add support for NTSTATUS values
The native NT API returns error values from a different namespace as the usual Win32 one. This means it needs to be typed differently. This commit adds broad support for using NTSTATUS values in a new type called NTStatus. First we add the type as a basic uint32. Then we add all of the predefined constants from ntstatus.h, by augmenting mkerrors.bash to do automatic extraction. There's a convenece way to convert an NT error to a Win32 error, so we add the NTStatus.Errno() function. Since NTStatus is an error type, we define an Error() function that returns a string by asking ntdll.dll for its contents, in the exact same way that syscall.Errno.Error() does, by calling FormatMessage. Since functions need to actually use this, we add the rule that if a `//sys` declaration returns an error value called "ntstatus", then the type underlying the error interface is an NTStatus instead of an Errno. Finally we fix one function that was returning an error interface of an Errno rather than an NTStatus. Change-Id: I06296b9563bbec526759d12a19f13ac6ad46dcc3 Reviewed-on: https://go-review.googlesource.com/c/sys/+/297330 Trust: Jason A. Donenfeld <Jason@zx2c4.com> Trust: Alex Brainman <alex.brainman@gmail.com> Run-TryBot: Jason A. Donenfeld <Jason@zx2c4.com> TryBot-Result: Go Bot <gobot@golang.org> Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
This commit is contained in:
Родитель
77cc2087c0
Коммит
134d130e1a
|
@ -9,6 +9,8 @@ shopt -s nullglob
|
|||
|
||||
winerror="$(printf '%s\n' "/mnt/c/Program Files (x86)/Windows Kits/"/*/Include/*/shared/winerror.h | sort -Vr | head -n 1)"
|
||||
[[ -n $winerror ]] || { echo "Unable to find winerror.h" >&2; exit 1; }
|
||||
ntstatus="$(printf '%s\n' "/mnt/c/Program Files (x86)/Windows Kits/"/*/Include/*/shared/ntstatus.h | sort -Vr | head -n 1)"
|
||||
[[ -n $ntstatus ]] || { echo "Unable to find ntstatus.h" >&2; exit 1; }
|
||||
|
||||
declare -A errors
|
||||
|
||||
|
@ -59,5 +61,10 @@ declare -A errors
|
|||
echo "$key $vtype = $value"
|
||||
done < "$winerror"
|
||||
|
||||
while read -r line; do
|
||||
[[ $line =~ ^#define\ (STATUS_[^\s]+)\ +\(\(NTSTATUS\)((0x)?[0-9a-fA-F]+)L?\) ]] || continue
|
||||
echo "${BASH_REMATCH[1]} NTStatus = ${BASH_REMATCH[2]}"
|
||||
done < "$ntstatus"
|
||||
|
||||
echo ")"
|
||||
} | gofmt > "zerrors_windows.go"
|
||||
|
|
|
@ -318,12 +318,18 @@ func (r *Rets) SetErrorCode() string {
|
|||
const code = `if r0 != 0 {
|
||||
%s = %sErrno(r0)
|
||||
}`
|
||||
const ntstatus = `if r0 != 0 {
|
||||
ntstatus = NTStatus(r0)
|
||||
}`
|
||||
if r.Name == "" && !r.ReturnsError {
|
||||
return ""
|
||||
}
|
||||
if r.Name == "" {
|
||||
return r.useLongHandleErrorCode("r1")
|
||||
}
|
||||
if r.Type == "error" && r.Name == "ntstatus" {
|
||||
return ntstatus
|
||||
}
|
||||
if r.Type == "error" {
|
||||
return fmt.Sprintf(code, r.Name, syscalldot())
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@ package windows
|
|||
|
||||
import (
|
||||
errorspkg "errors"
|
||||
"fmt"
|
||||
"sync"
|
||||
"syscall"
|
||||
"time"
|
||||
|
@ -65,9 +66,8 @@ const (
|
|||
LOCKFILE_FAIL_IMMEDIATELY = 0x00000001
|
||||
LOCKFILE_EXCLUSIVE_LOCK = 0x00000002
|
||||
|
||||
// Return values of SleepEx and other APC functions
|
||||
STATUS_USER_APC = 0x000000C0
|
||||
WAIT_IO_COMPLETION = STATUS_USER_APC
|
||||
// Return value of SleepEx and other APC functions
|
||||
WAIT_IO_COMPLETION = 0x000000C0
|
||||
)
|
||||
|
||||
// StringToUTF16 is deprecated. Use UTF16FromString instead.
|
||||
|
@ -375,7 +375,8 @@ func NewCallbackCDecl(fn interface{}) uintptr {
|
|||
//sys stringFromGUID2(rguid *GUID, lpsz *uint16, cchMax int32) (chars int32) = ole32.StringFromGUID2
|
||||
//sys coCreateGuid(pguid *GUID) (ret error) = ole32.CoCreateGuid
|
||||
//sys CoTaskMemFree(address unsafe.Pointer) = ole32.CoTaskMemFree
|
||||
//sys rtlGetVersion(info *OsVersionInfoEx) (ret error) = ntdll.RtlGetVersion
|
||||
//sys rtlNtStatusToDosError(ntstatus NTStatus) (ret syscall.Errno) = ntdll.RtlNtStatusToDosError
|
||||
//sys rtlGetVersion(info *OsVersionInfoEx) (ntstatus error) = ntdll.RtlGetVersion
|
||||
//sys rtlGetNtVersionNumbers(majorVersion *uint32, minorVersion *uint32, buildNumber *uint32) = ntdll.RtlGetNtVersionNumbers
|
||||
//sys getProcessPreferredUILanguages(flags uint32, numLanguages *uint32, buf *uint16, bufSize *uint32) (err error) = kernel32.GetProcessPreferredUILanguages
|
||||
//sys getThreadPreferredUILanguages(flags uint32, numLanguages *uint32, buf *uint16, bufSize *uint32) (err error) = kernel32.GetThreadPreferredUILanguages
|
||||
|
@ -1514,3 +1515,21 @@ func getUILanguages(flags uint32, f func(flags uint32, numLanguages *uint32, buf
|
|||
func SetConsoleCursorPosition(console Handle, position Coord) error {
|
||||
return setConsoleCursorPosition(console, *((*uint32)(unsafe.Pointer(&position))))
|
||||
}
|
||||
|
||||
func (s NTStatus) Errno() syscall.Errno {
|
||||
return rtlNtStatusToDosError(s)
|
||||
}
|
||||
|
||||
func langID(pri, sub uint16) uint32 { return uint32(sub)<<10 | uint32(pri) }
|
||||
|
||||
func (s NTStatus) Error() string {
|
||||
b := make([]uint16, 300)
|
||||
n, err := FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_FROM_HMODULE|FORMAT_MESSAGE_ARGUMENT_ARRAY, modntdll.Handle(), uint32(s), langID(LANG_ENGLISH, SUBLANG_ENGLISH_US), b, nil)
|
||||
if err != nil {
|
||||
return fmt.Sprintf("NTSTATUS 0x%08x", uint32(s))
|
||||
}
|
||||
// trim terminating \r and \n
|
||||
for ; n > 0 && (b[n-1] == '\n' || b[n-1] == '\r'); n-- {
|
||||
}
|
||||
return string(utf16.Decode(b[:n]))
|
||||
}
|
||||
|
|
|
@ -486,3 +486,11 @@ func TestIsWow64Process2(t *testing.T) {
|
|||
t.Errorf("IsWow64Process2 is wrong: want %v have %v", runtime.GOARCH, processMachine)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNTStatusString(t *testing.T) {
|
||||
want := "The name limit for the local computer network adapter card was exceeded."
|
||||
got := windows.STATUS_TOO_MANY_NAMES.Error()
|
||||
if want != got {
|
||||
t.Errorf("NTStatus.Error did not return an expected error string - want %q; got %q", want, got)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,6 +10,10 @@ import (
|
|||
"unsafe"
|
||||
)
|
||||
|
||||
// NTStatus corresponds with NTSTATUS, error values returned by ntdll.dll and
|
||||
// other native functions.
|
||||
type NTStatus uint32
|
||||
|
||||
const (
|
||||
// Invented values to support what package os expects.
|
||||
O_RDONLY = 0x00000
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -346,6 +346,7 @@ var (
|
|||
procNetUserGetInfo = modnetapi32.NewProc("NetUserGetInfo")
|
||||
procRtlGetNtVersionNumbers = modntdll.NewProc("RtlGetNtVersionNumbers")
|
||||
procRtlGetVersion = modntdll.NewProc("RtlGetVersion")
|
||||
procRtlNtStatusToDosError = modntdll.NewProc("RtlNtStatusToDosError")
|
||||
procCLSIDFromString = modole32.NewProc("CLSIDFromString")
|
||||
procCoCreateGuid = modole32.NewProc("CoCreateGuid")
|
||||
procCoTaskMemFree = modole32.NewProc("CoTaskMemFree")
|
||||
|
@ -2951,14 +2952,20 @@ func rtlGetNtVersionNumbers(majorVersion *uint32, minorVersion *uint32, buildNum
|
|||
return
|
||||
}
|
||||
|
||||
func rtlGetVersion(info *OsVersionInfoEx) (ret error) {
|
||||
func rtlGetVersion(info *OsVersionInfoEx) (ntstatus error) {
|
||||
r0, _, _ := syscall.Syscall(procRtlGetVersion.Addr(), 1, uintptr(unsafe.Pointer(info)), 0, 0)
|
||||
if r0 != 0 {
|
||||
ret = syscall.Errno(r0)
|
||||
ntstatus = NTStatus(r0)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func rtlNtStatusToDosError(ntstatus NTStatus) (ret syscall.Errno) {
|
||||
r0, _, _ := syscall.Syscall(procRtlNtStatusToDosError.Addr(), 1, uintptr(ntstatus), 0, 0)
|
||||
ret = syscall.Errno(r0)
|
||||
return
|
||||
}
|
||||
|
||||
func clsidFromString(lpsz *uint16, pclsid *GUID) (ret error) {
|
||||
r0, _, _ := syscall.Syscall(procCLSIDFromString.Addr(), 2, uintptr(unsafe.Pointer(lpsz)), uintptr(unsafe.Pointer(pclsid)), 0)
|
||||
if r0 != 0 {
|
||||
|
|
Загрузка…
Ссылка в новой задаче