mirror of
https://github.com/rwinkhart/sys.git
synced 2026-09-05 16:47:27 -04:00
go.sys: copy files from syscall package to go.sys/{plan9,windows,unix}
This CL copies to each package of go.sys the files from syscall it will need.
Different directories have different files, but these:
mkall.sh
str.go
syscall.go
mksyscall.pl
race.go
race0.go
syscall_test.go
are copied to all three.
No changes yet, these are just copies. They are not ready to use yet:
package names are wrong, for starters. But this clean copy will make
it easier to follow the changes as the packages are enabled.
LGTM=rsc
R=golang-codereviews, rsc
CC=golang-codereviews
https://golang.org/cl/126960043
This commit is contained in:
@@ -0,0 +1,7 @@
|
||||
// Copyright 2009 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//
|
||||
// System calls for 386, Windows are implemented in ../runtime/syscall_windows.goc
|
||||
//
|
||||
@@ -0,0 +1,7 @@
|
||||
// Copyright 2009 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//
|
||||
// System calls for amd64, Windows are implemented in ../runtime/syscall_windows.goc
|
||||
//
|
||||
@@ -0,0 +1,279 @@
|
||||
// Copyright 2011 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package syscall
|
||||
|
||||
import (
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// DLLError describes reasons for DLL load failures.
|
||||
type DLLError struct {
|
||||
Err error
|
||||
ObjName string
|
||||
Msg string
|
||||
}
|
||||
|
||||
func (e *DLLError) Error() string { return e.Msg }
|
||||
|
||||
// Implemented in ../runtime/syscall_windows.goc.
|
||||
func Syscall(trap, nargs, a1, a2, a3 uintptr) (r1, r2 uintptr, err Errno)
|
||||
func Syscall6(trap, nargs, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err Errno)
|
||||
func Syscall9(trap, nargs, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2 uintptr, err Errno)
|
||||
func Syscall12(trap, nargs, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12 uintptr) (r1, r2 uintptr, err Errno)
|
||||
func Syscall15(trap, nargs, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15 uintptr) (r1, r2 uintptr, err Errno)
|
||||
func loadlibrary(filename *uint16) (handle uintptr, err Errno)
|
||||
func getprocaddress(handle uintptr, procname *uint8) (proc uintptr, err Errno)
|
||||
|
||||
// A DLL implements access to a single DLL.
|
||||
type DLL struct {
|
||||
Name string
|
||||
Handle Handle
|
||||
}
|
||||
|
||||
// LoadDLL loads DLL file into memory.
|
||||
func LoadDLL(name string) (dll *DLL, err error) {
|
||||
namep, err := UTF16PtrFromString(name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
h, e := loadlibrary(namep)
|
||||
if e != 0 {
|
||||
return nil, &DLLError{
|
||||
Err: e,
|
||||
ObjName: name,
|
||||
Msg: "Failed to load " + name + ": " + e.Error(),
|
||||
}
|
||||
}
|
||||
d := &DLL{
|
||||
Name: name,
|
||||
Handle: Handle(h),
|
||||
}
|
||||
return d, nil
|
||||
}
|
||||
|
||||
// MustLoadDLL is like LoadDLL but panics if load operation failes.
|
||||
func MustLoadDLL(name string) *DLL {
|
||||
d, e := LoadDLL(name)
|
||||
if e != nil {
|
||||
panic(e)
|
||||
}
|
||||
return d
|
||||
}
|
||||
|
||||
// FindProc searches DLL d for procedure named name and returns *Proc
|
||||
// if found. It returns an error if search fails.
|
||||
func (d *DLL) FindProc(name string) (proc *Proc, err error) {
|
||||
namep, err := BytePtrFromString(name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
a, e := getprocaddress(uintptr(d.Handle), namep)
|
||||
if e != 0 {
|
||||
return nil, &DLLError{
|
||||
Err: e,
|
||||
ObjName: name,
|
||||
Msg: "Failed to find " + name + " procedure in " + d.Name + ": " + e.Error(),
|
||||
}
|
||||
}
|
||||
p := &Proc{
|
||||
Dll: d,
|
||||
Name: name,
|
||||
addr: a,
|
||||
}
|
||||
return p, nil
|
||||
}
|
||||
|
||||
// MustFindProc is like FindProc but panics if search fails.
|
||||
func (d *DLL) MustFindProc(name string) *Proc {
|
||||
p, e := d.FindProc(name)
|
||||
if e != nil {
|
||||
panic(e)
|
||||
}
|
||||
return p
|
||||
}
|
||||
|
||||
// Release unloads DLL d from memory.
|
||||
func (d *DLL) Release() (err error) {
|
||||
return FreeLibrary(d.Handle)
|
||||
}
|
||||
|
||||
// A Proc implements access to a procedure inside a DLL.
|
||||
type Proc struct {
|
||||
Dll *DLL
|
||||
Name string
|
||||
addr uintptr
|
||||
}
|
||||
|
||||
// Addr returns the address of the procedure represented by p.
|
||||
// The return value can be passed to Syscall to run the procedure.
|
||||
func (p *Proc) Addr() uintptr {
|
||||
return p.addr
|
||||
}
|
||||
|
||||
// Call executes procedure p with arguments a. It will panic, if more then 15 arguments
|
||||
// are supplied.
|
||||
//
|
||||
// The returned error is always non-nil, constructed from the result of GetLastError.
|
||||
// Callers must inspect the primary return value to decide whether an error occurred
|
||||
// (according to the semantics of the specific function being called) before consulting
|
||||
// the error. The error will be guaranteed to contain syscall.Errno.
|
||||
func (p *Proc) Call(a ...uintptr) (r1, r2 uintptr, lastErr error) {
|
||||
switch len(a) {
|
||||
case 0:
|
||||
return Syscall(p.Addr(), uintptr(len(a)), 0, 0, 0)
|
||||
case 1:
|
||||
return Syscall(p.Addr(), uintptr(len(a)), a[0], 0, 0)
|
||||
case 2:
|
||||
return Syscall(p.Addr(), uintptr(len(a)), a[0], a[1], 0)
|
||||
case 3:
|
||||
return Syscall(p.Addr(), uintptr(len(a)), a[0], a[1], a[2])
|
||||
case 4:
|
||||
return Syscall6(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], 0, 0)
|
||||
case 5:
|
||||
return Syscall6(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], 0)
|
||||
case 6:
|
||||
return Syscall6(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5])
|
||||
case 7:
|
||||
return Syscall9(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], 0, 0)
|
||||
case 8:
|
||||
return Syscall9(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], 0)
|
||||
case 9:
|
||||
return Syscall9(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8])
|
||||
case 10:
|
||||
return Syscall12(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], 0, 0)
|
||||
case 11:
|
||||
return Syscall12(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10], 0)
|
||||
case 12:
|
||||
return Syscall12(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10], a[11])
|
||||
case 13:
|
||||
return Syscall15(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10], a[11], a[12], 0, 0)
|
||||
case 14:
|
||||
return Syscall15(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10], a[11], a[12], a[13], 0)
|
||||
case 15:
|
||||
return Syscall15(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10], a[11], a[12], a[13], a[14])
|
||||
default:
|
||||
panic("Call " + p.Name + " with too many arguments " + itoa(len(a)) + ".")
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// A LazyDLL implements access to a single DLL.
|
||||
// It will delay the load of the DLL until the first
|
||||
// call to its Handle method or to one of its
|
||||
// LazyProc's Addr method.
|
||||
type LazyDLL struct {
|
||||
mu sync.Mutex
|
||||
dll *DLL // non nil once DLL is loaded
|
||||
Name string
|
||||
}
|
||||
|
||||
// Load loads DLL file d.Name into memory. It returns an error if fails.
|
||||
// Load will not try to load DLL, if it is already loaded into memory.
|
||||
func (d *LazyDLL) Load() error {
|
||||
// Non-racy version of:
|
||||
// if d.dll == nil {
|
||||
if atomic.LoadPointer((*unsafe.Pointer)(unsafe.Pointer(&d.dll))) == nil {
|
||||
d.mu.Lock()
|
||||
defer d.mu.Unlock()
|
||||
if d.dll == nil {
|
||||
dll, e := LoadDLL(d.Name)
|
||||
if e != nil {
|
||||
return e
|
||||
}
|
||||
// Non-racy version of:
|
||||
// d.dll = dll
|
||||
atomic.StorePointer((*unsafe.Pointer)(unsafe.Pointer(&d.dll)), unsafe.Pointer(dll))
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// mustLoad is like Load but panics if search fails.
|
||||
func (d *LazyDLL) mustLoad() {
|
||||
e := d.Load()
|
||||
if e != nil {
|
||||
panic(e)
|
||||
}
|
||||
}
|
||||
|
||||
// Handle returns d's module handle.
|
||||
func (d *LazyDLL) Handle() uintptr {
|
||||
d.mustLoad()
|
||||
return uintptr(d.dll.Handle)
|
||||
}
|
||||
|
||||
// NewProc returns a LazyProc for accessing the named procedure in the DLL d.
|
||||
func (d *LazyDLL) NewProc(name string) *LazyProc {
|
||||
return &LazyProc{l: d, Name: name}
|
||||
}
|
||||
|
||||
// NewLazyDLL creates new LazyDLL associated with DLL file.
|
||||
func NewLazyDLL(name string) *LazyDLL {
|
||||
return &LazyDLL{Name: name}
|
||||
}
|
||||
|
||||
// A LazyProc implements access to a procedure inside a LazyDLL.
|
||||
// It delays the lookup until the Addr method is called.
|
||||
type LazyProc struct {
|
||||
mu sync.Mutex
|
||||
Name string
|
||||
l *LazyDLL
|
||||
proc *Proc
|
||||
}
|
||||
|
||||
// Find searches DLL for procedure named p.Name. It returns
|
||||
// an error if search fails. Find will not search procedure,
|
||||
// if it is already found and loaded into memory.
|
||||
func (p *LazyProc) Find() error {
|
||||
// Non-racy version of:
|
||||
// if p.proc == nil {
|
||||
if atomic.LoadPointer((*unsafe.Pointer)(unsafe.Pointer(&p.proc))) == nil {
|
||||
p.mu.Lock()
|
||||
defer p.mu.Unlock()
|
||||
if p.proc == nil {
|
||||
e := p.l.Load()
|
||||
if e != nil {
|
||||
return e
|
||||
}
|
||||
proc, e := p.l.dll.FindProc(p.Name)
|
||||
if e != nil {
|
||||
return e
|
||||
}
|
||||
// Non-racy version of:
|
||||
// p.proc = proc
|
||||
atomic.StorePointer((*unsafe.Pointer)(unsafe.Pointer(&p.proc)), unsafe.Pointer(proc))
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// mustFind is like Find but panics if search fails.
|
||||
func (p *LazyProc) mustFind() {
|
||||
e := p.Find()
|
||||
if e != nil {
|
||||
panic(e)
|
||||
}
|
||||
}
|
||||
|
||||
// Addr returns the address of the procedure represented by p.
|
||||
// The return value can be passed to Syscall to run the procedure.
|
||||
func (p *LazyProc) Addr() uintptr {
|
||||
p.mustFind()
|
||||
return p.proc.Addr()
|
||||
}
|
||||
|
||||
// Call executes procedure p with arguments a. It will panic, if more then 15 arguments
|
||||
// are supplied.
|
||||
//
|
||||
// The returned error is always non-nil, constructed from the result of GetLastError.
|
||||
// Callers must inspect the primary return value to decide whether an error occurred
|
||||
// (according to the semantics of the specific function being called) before consulting
|
||||
// the error. The error will be guaranteed to contain syscall.Errno.
|
||||
func (p *LazyProc) Call(a ...uintptr) (r1, r2 uintptr, lastErr error) {
|
||||
p.mustFind()
|
||||
return p.proc.Call(a...)
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
// Copyright 2010 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Windows environment variables.
|
||||
|
||||
package syscall
|
||||
|
||||
import (
|
||||
"unicode/utf16"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
func Getenv(key string) (value string, found bool) {
|
||||
keyp, err := UTF16PtrFromString(key)
|
||||
if err != nil {
|
||||
return "", false
|
||||
}
|
||||
b := make([]uint16, 100)
|
||||
n, e := GetEnvironmentVariable(keyp, &b[0], uint32(len(b)))
|
||||
if n == 0 && e == ERROR_ENVVAR_NOT_FOUND {
|
||||
return "", false
|
||||
}
|
||||
if n > uint32(len(b)) {
|
||||
b = make([]uint16, n)
|
||||
n, e = GetEnvironmentVariable(keyp, &b[0], uint32(len(b)))
|
||||
if n > uint32(len(b)) {
|
||||
n = 0
|
||||
}
|
||||
}
|
||||
return string(utf16.Decode(b[0:n])), true
|
||||
}
|
||||
|
||||
func Setenv(key, value string) error {
|
||||
v, err := UTF16PtrFromString(value)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
keyp, err := UTF16PtrFromString(key)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
e := SetEnvironmentVariable(keyp, v)
|
||||
if e != nil {
|
||||
return e
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func Clearenv() {
|
||||
for _, s := range Environ() {
|
||||
// Environment variables can begin with =
|
||||
// so start looking for the separator = at j=1.
|
||||
// http://blogs.msdn.com/b/oldnewthing/archive/2010/05/06/10008132.aspx
|
||||
for j := 1; j < len(s); j++ {
|
||||
if s[j] == '=' {
|
||||
Setenv(s[0:j], "")
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func Environ() []string {
|
||||
s, e := GetEnvironmentStrings()
|
||||
if e != nil {
|
||||
return nil
|
||||
}
|
||||
defer FreeEnvironmentStrings(s)
|
||||
r := make([]string, 0, 50) // Empty with room to grow.
|
||||
for from, i, p := 0, 0, (*[1 << 24]uint16)(unsafe.Pointer(s)); true; i++ {
|
||||
if p[i] == 0 {
|
||||
// empty string marks the end
|
||||
if i <= from {
|
||||
break
|
||||
}
|
||||
r = append(r, string(utf16.Decode(p[from:i])))
|
||||
from = i + 1
|
||||
}
|
||||
}
|
||||
return r
|
||||
}
|
||||
@@ -0,0 +1,341 @@
|
||||
// Copyright 2009 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Fork, exec, wait, etc.
|
||||
|
||||
package syscall
|
||||
|
||||
import (
|
||||
"sync"
|
||||
"unicode/utf16"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
var ForkLock sync.RWMutex
|
||||
|
||||
// EscapeArg rewrites command line argument s as prescribed
|
||||
// in http://msdn.microsoft.com/en-us/library/ms880421.
|
||||
// This function returns "" (2 double quotes) if s is empty.
|
||||
// Alternatively, these transformations are done:
|
||||
// - every back slash (\) is doubled, but only if immediately
|
||||
// followed by double quote (");
|
||||
// - every double quote (") is escaped by back slash (\);
|
||||
// - finally, s is wrapped with double quotes (arg -> "arg"),
|
||||
// but only if there is space or tab inside s.
|
||||
func EscapeArg(s string) string {
|
||||
if len(s) == 0 {
|
||||
return "\"\""
|
||||
}
|
||||
n := len(s)
|
||||
hasSpace := false
|
||||
for i := 0; i < len(s); i++ {
|
||||
switch s[i] {
|
||||
case '"', '\\':
|
||||
n++
|
||||
case ' ', '\t':
|
||||
hasSpace = true
|
||||
}
|
||||
}
|
||||
if hasSpace {
|
||||
n += 2
|
||||
}
|
||||
if n == len(s) {
|
||||
return s
|
||||
}
|
||||
|
||||
qs := make([]byte, n)
|
||||
j := 0
|
||||
if hasSpace {
|
||||
qs[j] = '"'
|
||||
j++
|
||||
}
|
||||
slashes := 0
|
||||
for i := 0; i < len(s); i++ {
|
||||
switch s[i] {
|
||||
default:
|
||||
slashes = 0
|
||||
qs[j] = s[i]
|
||||
case '\\':
|
||||
slashes++
|
||||
qs[j] = s[i]
|
||||
case '"':
|
||||
for ; slashes > 0; slashes-- {
|
||||
qs[j] = '\\'
|
||||
j++
|
||||
}
|
||||
qs[j] = '\\'
|
||||
j++
|
||||
qs[j] = s[i]
|
||||
}
|
||||
j++
|
||||
}
|
||||
if hasSpace {
|
||||
for ; slashes > 0; slashes-- {
|
||||
qs[j] = '\\'
|
||||
j++
|
||||
}
|
||||
qs[j] = '"'
|
||||
j++
|
||||
}
|
||||
return string(qs[:j])
|
||||
}
|
||||
|
||||
// makeCmdLine builds a command line out of args by escaping "special"
|
||||
// characters and joining the arguments with spaces.
|
||||
func makeCmdLine(args []string) string {
|
||||
var s string
|
||||
for _, v := range args {
|
||||
if s != "" {
|
||||
s += " "
|
||||
}
|
||||
s += EscapeArg(v)
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
// createEnvBlock converts an array of environment strings into
|
||||
// the representation required by CreateProcess: a sequence of NUL
|
||||
// terminated strings followed by a nil.
|
||||
// Last bytes are two UCS-2 NULs, or four NUL bytes.
|
||||
func createEnvBlock(envv []string) *uint16 {
|
||||
if len(envv) == 0 {
|
||||
return &utf16.Encode([]rune("\x00\x00"))[0]
|
||||
}
|
||||
length := 0
|
||||
for _, s := range envv {
|
||||
length += len(s) + 1
|
||||
}
|
||||
length += 1
|
||||
|
||||
b := make([]byte, length)
|
||||
i := 0
|
||||
for _, s := range envv {
|
||||
l := len(s)
|
||||
copy(b[i:i+l], []byte(s))
|
||||
copy(b[i+l:i+l+1], []byte{0})
|
||||
i = i + l + 1
|
||||
}
|
||||
copy(b[i:i+1], []byte{0})
|
||||
|
||||
return &utf16.Encode([]rune(string(b)))[0]
|
||||
}
|
||||
|
||||
func CloseOnExec(fd Handle) {
|
||||
SetHandleInformation(Handle(fd), HANDLE_FLAG_INHERIT, 0)
|
||||
}
|
||||
|
||||
func SetNonblock(fd Handle, nonblocking bool) (err error) {
|
||||
return nil
|
||||
}
|
||||
|
||||
// getFullPath retrieves the full path of the specified file.
|
||||
// Just a wrapper for Windows GetFullPathName api.
|
||||
func getFullPath(name string) (path string, err error) {
|
||||
p, err := UTF16PtrFromString(name)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
buf := make([]uint16, 100)
|
||||
n, err := GetFullPathName(p, uint32(len(buf)), &buf[0], nil)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if n > uint32(len(buf)) {
|
||||
// Windows is asking for bigger buffer.
|
||||
buf = make([]uint16, n)
|
||||
n, err = GetFullPathName(p, uint32(len(buf)), &buf[0], nil)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if n > uint32(len(buf)) {
|
||||
return "", EINVAL
|
||||
}
|
||||
}
|
||||
return UTF16ToString(buf[:n]), nil
|
||||
}
|
||||
|
||||
func isSlash(c uint8) bool {
|
||||
return c == '\\' || c == '/'
|
||||
}
|
||||
|
||||
func normalizeDir(dir string) (name string, err error) {
|
||||
ndir, err := getFullPath(dir)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if len(ndir) > 2 && isSlash(ndir[0]) && isSlash(ndir[1]) {
|
||||
// dir cannot have \\server\share\path form
|
||||
return "", EINVAL
|
||||
}
|
||||
return ndir, nil
|
||||
}
|
||||
|
||||
func volToUpper(ch int) int {
|
||||
if 'a' <= ch && ch <= 'z' {
|
||||
ch += 'A' - 'a'
|
||||
}
|
||||
return ch
|
||||
}
|
||||
|
||||
func joinExeDirAndFName(dir, p string) (name string, err error) {
|
||||
if len(p) == 0 {
|
||||
return "", EINVAL
|
||||
}
|
||||
if len(p) > 2 && isSlash(p[0]) && isSlash(p[1]) {
|
||||
// \\server\share\path form
|
||||
return p, nil
|
||||
}
|
||||
if len(p) > 1 && p[1] == ':' {
|
||||
// has drive letter
|
||||
if len(p) == 2 {
|
||||
return "", EINVAL
|
||||
}
|
||||
if isSlash(p[2]) {
|
||||
return p, nil
|
||||
} else {
|
||||
d, err := normalizeDir(dir)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if volToUpper(int(p[0])) == volToUpper(int(d[0])) {
|
||||
return getFullPath(d + "\\" + p[2:])
|
||||
} else {
|
||||
return getFullPath(p)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// no drive letter
|
||||
d, err := normalizeDir(dir)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if isSlash(p[0]) {
|
||||
return getFullPath(d[:2] + p)
|
||||
} else {
|
||||
return getFullPath(d + "\\" + p)
|
||||
}
|
||||
}
|
||||
// we shouldn't be here
|
||||
return "", EINVAL
|
||||
}
|
||||
|
||||
type ProcAttr struct {
|
||||
Dir string
|
||||
Env []string
|
||||
Files []uintptr
|
||||
Sys *SysProcAttr
|
||||
}
|
||||
|
||||
type SysProcAttr struct {
|
||||
HideWindow bool
|
||||
CmdLine string // used if non-empty, else the windows command line is built by escaping the arguments passed to StartProcess
|
||||
CreationFlags uint32
|
||||
}
|
||||
|
||||
var zeroProcAttr ProcAttr
|
||||
var zeroSysProcAttr SysProcAttr
|
||||
|
||||
func StartProcess(argv0 string, argv []string, attr *ProcAttr) (pid int, handle uintptr, err error) {
|
||||
if len(argv0) == 0 {
|
||||
return 0, 0, EWINDOWS
|
||||
}
|
||||
if attr == nil {
|
||||
attr = &zeroProcAttr
|
||||
}
|
||||
sys := attr.Sys
|
||||
if sys == nil {
|
||||
sys = &zeroSysProcAttr
|
||||
}
|
||||
|
||||
if len(attr.Files) > 3 {
|
||||
return 0, 0, EWINDOWS
|
||||
}
|
||||
|
||||
if len(attr.Dir) != 0 {
|
||||
// StartProcess assumes that argv0 is relative to attr.Dir,
|
||||
// because it implies Chdir(attr.Dir) before executing argv0.
|
||||
// Windows CreateProcess assumes the opposite: it looks for
|
||||
// argv0 relative to the current directory, and, only once the new
|
||||
// process is started, it does Chdir(attr.Dir). We are adjusting
|
||||
// for that difference here by making argv0 absolute.
|
||||
var err error
|
||||
argv0, err = joinExeDirAndFName(attr.Dir, argv0)
|
||||
if err != nil {
|
||||
return 0, 0, err
|
||||
}
|
||||
}
|
||||
argv0p, err := UTF16PtrFromString(argv0)
|
||||
if err != nil {
|
||||
return 0, 0, err
|
||||
}
|
||||
|
||||
var cmdline string
|
||||
// Windows CreateProcess takes the command line as a single string:
|
||||
// use attr.CmdLine if set, else build the command line by escaping
|
||||
// and joining each argument with spaces
|
||||
if sys.CmdLine != "" {
|
||||
cmdline = sys.CmdLine
|
||||
} else {
|
||||
cmdline = makeCmdLine(argv)
|
||||
}
|
||||
|
||||
var argvp *uint16
|
||||
if len(cmdline) != 0 {
|
||||
argvp, err = UTF16PtrFromString(cmdline)
|
||||
if err != nil {
|
||||
return 0, 0, err
|
||||
}
|
||||
}
|
||||
|
||||
var dirp *uint16
|
||||
if len(attr.Dir) != 0 {
|
||||
dirp, err = UTF16PtrFromString(attr.Dir)
|
||||
if err != nil {
|
||||
return 0, 0, err
|
||||
}
|
||||
}
|
||||
|
||||
// Acquire the fork lock so that no other threads
|
||||
// create new fds that are not yet close-on-exec
|
||||
// before we fork.
|
||||
ForkLock.Lock()
|
||||
defer ForkLock.Unlock()
|
||||
|
||||
p, _ := GetCurrentProcess()
|
||||
fd := make([]Handle, len(attr.Files))
|
||||
for i := range attr.Files {
|
||||
if attr.Files[i] > 0 {
|
||||
err := DuplicateHandle(p, Handle(attr.Files[i]), p, &fd[i], 0, true, DUPLICATE_SAME_ACCESS)
|
||||
if err != nil {
|
||||
return 0, 0, err
|
||||
}
|
||||
defer CloseHandle(Handle(fd[i]))
|
||||
}
|
||||
}
|
||||
si := new(StartupInfo)
|
||||
si.Cb = uint32(unsafe.Sizeof(*si))
|
||||
si.Flags = STARTF_USESTDHANDLES
|
||||
if sys.HideWindow {
|
||||
si.Flags |= STARTF_USESHOWWINDOW
|
||||
si.ShowWindow = SW_HIDE
|
||||
}
|
||||
si.StdInput = fd[0]
|
||||
si.StdOutput = fd[1]
|
||||
si.StdErr = fd[2]
|
||||
|
||||
pi := new(ProcessInformation)
|
||||
|
||||
flags := sys.CreationFlags | CREATE_UNICODE_ENVIRONMENT
|
||||
err = CreateProcess(argv0p, argvp, nil, nil, true, flags, createEnvBlock(attr.Env), dirp, si, pi)
|
||||
if err != nil {
|
||||
return 0, 0, err
|
||||
}
|
||||
defer CloseHandle(Handle(pi.Thread))
|
||||
|
||||
return int(pi.ProcessId), uintptr(pi.Process), nil
|
||||
}
|
||||
|
||||
func Exec(argv0 string, argv []string, envv []string) (err error) {
|
||||
return EWINDOWS
|
||||
}
|
||||
Executable
+263
@@ -0,0 +1,263 @@
|
||||
#!/usr/bin/env bash
|
||||
# Copyright 2009 The Go Authors. All rights reserved.
|
||||
# Use of this source code is governed by a BSD-style
|
||||
# license that can be found in the LICENSE file.
|
||||
|
||||
# The syscall package provides access to the raw system call
|
||||
# interface of the underlying operating system. Porting Go to
|
||||
# a new architecture/operating system combination requires
|
||||
# some manual effort, though there are tools that automate
|
||||
# much of the process. The auto-generated files have names
|
||||
# beginning with z.
|
||||
#
|
||||
# This script runs or (given -n) prints suggested commands to generate z files
|
||||
# for the current system. Running those commands is not automatic.
|
||||
# This script is documentation more than anything else.
|
||||
#
|
||||
# * asm_${GOOS}_${GOARCH}.s
|
||||
#
|
||||
# This hand-written assembly file implements system call dispatch.
|
||||
# There are three entry points:
|
||||
#
|
||||
# func Syscall(trap, a1, a2, a3 uintptr) (r1, r2, err uintptr);
|
||||
# func Syscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintptr);
|
||||
# func RawSyscall(trap, a1, a2, a3 uintptr) (r1, r2, err uintptr);
|
||||
#
|
||||
# The first and second are the standard ones; they differ only in
|
||||
# how many arguments can be passed to the kernel.
|
||||
# The third is for low-level use by the ForkExec wrapper;
|
||||
# unlike the first two, it does not call into the scheduler to
|
||||
# let it know that a system call is running.
|
||||
#
|
||||
# * syscall_${GOOS}.go
|
||||
#
|
||||
# This hand-written Go file implements system calls that need
|
||||
# special handling and lists "//sys" comments giving prototypes
|
||||
# for ones that can be auto-generated. Mksyscall reads those
|
||||
# comments to generate the stubs.
|
||||
#
|
||||
# * syscall_${GOOS}_${GOARCH}.go
|
||||
#
|
||||
# Same as syscall_${GOOS}.go except that it contains code specific
|
||||
# to ${GOOS} on one particular architecture.
|
||||
#
|
||||
# * types_${GOOS}.c
|
||||
#
|
||||
# This hand-written C file includes standard C headers and then
|
||||
# creates typedef or enum names beginning with a dollar sign
|
||||
# (use of $ in variable names is a gcc extension). The hardest
|
||||
# part about preparing this file is figuring out which headers to
|
||||
# include and which symbols need to be #defined to get the
|
||||
# actual data structures that pass through to the kernel system calls.
|
||||
# Some C libraries present alternate versions for binary compatibility
|
||||
# and translate them on the way in and out of system calls, but
|
||||
# there is almost always a #define that can get the real ones.
|
||||
# See types_darwin.c and types_linux.c for examples.
|
||||
#
|
||||
# * zerror_${GOOS}_${GOARCH}.go
|
||||
#
|
||||
# This machine-generated file defines the system's error numbers,
|
||||
# error strings, and signal numbers. The generator is "mkerrors.sh".
|
||||
# Usually no arguments are needed, but mkerrors.sh will pass its
|
||||
# arguments on to godefs.
|
||||
#
|
||||
# * zsyscall_${GOOS}_${GOARCH}.go
|
||||
#
|
||||
# Generated by mksyscall.pl; see syscall_${GOOS}.go above.
|
||||
#
|
||||
# * zsysnum_${GOOS}_${GOARCH}.go
|
||||
#
|
||||
# Generated by mksysnum_${GOOS}.
|
||||
#
|
||||
# * ztypes_${GOOS}_${GOARCH}.go
|
||||
#
|
||||
# Generated by godefs; see types_${GOOS}.c above.
|
||||
|
||||
GOOSARCH="${GOOS}_${GOARCH}"
|
||||
|
||||
# defaults
|
||||
mksyscall="./mksyscall.pl"
|
||||
mkerrors="./mkerrors.sh"
|
||||
zerrors="zerrors_$GOOSARCH.go"
|
||||
mksysctl=""
|
||||
zsysctl="zsysctl_$GOOSARCH.go"
|
||||
mksysnum=
|
||||
mktypes=
|
||||
run="sh"
|
||||
|
||||
case "$1" in
|
||||
-syscalls)
|
||||
for i in zsyscall*go
|
||||
do
|
||||
sed 1q $i | sed 's;^// ;;' | sh > _$i && gofmt < _$i > $i
|
||||
rm _$i
|
||||
done
|
||||
exit 0
|
||||
;;
|
||||
-n)
|
||||
run="cat"
|
||||
shift
|
||||
esac
|
||||
|
||||
case "$#" in
|
||||
0)
|
||||
;;
|
||||
*)
|
||||
echo 'usage: mkall.sh [-n]' 1>&2
|
||||
exit 2
|
||||
esac
|
||||
|
||||
case "$GOOSARCH" in
|
||||
_* | *_ | _)
|
||||
echo 'undefined $GOOS_$GOARCH:' "$GOOSARCH" 1>&2
|
||||
exit 1
|
||||
;;
|
||||
darwin_386)
|
||||
mkerrors="$mkerrors -m32"
|
||||
mksyscall="./mksyscall.pl -l32"
|
||||
mksysnum="./mksysnum_darwin.pl /usr/include/sys/syscall.h"
|
||||
mktypes="GOARCH=$GOARCH go tool cgo -godefs"
|
||||
;;
|
||||
darwin_amd64)
|
||||
mkerrors="$mkerrors -m64"
|
||||
mksysnum="./mksysnum_darwin.pl /usr/include/sys/syscall.h"
|
||||
mktypes="GOARCH=$GOARCH go tool cgo -godefs"
|
||||
;;
|
||||
dragonfly_386)
|
||||
mkerrors="$mkerrors -m32"
|
||||
mksyscall="./mksyscall.pl -l32 -dragonfly"
|
||||
mksysnum="curl -s 'http://gitweb.dragonflybsd.org/dragonfly.git/blob_plain/HEAD:/sys/kern/syscalls.master' | ./mksysnum_dragonfly.pl"
|
||||
mktypes="GOARCH=$GOARCH go tool cgo -godefs"
|
||||
;;
|
||||
dragonfly_amd64)
|
||||
mkerrors="$mkerrors -m64"
|
||||
mksyscall="./mksyscall.pl -dragonfly"
|
||||
mksysnum="curl -s 'http://gitweb.dragonflybsd.org/dragonfly.git/blob_plain/HEAD:/sys/kern/syscalls.master' | ./mksysnum_dragonfly.pl"
|
||||
mktypes="GOARCH=$GOARCH go tool cgo -godefs"
|
||||
;;
|
||||
freebsd_386)
|
||||
mkerrors="$mkerrors -m32"
|
||||
mksyscall="./mksyscall.pl -l32"
|
||||
mksysnum="curl -s 'http://svn.freebsd.org/base/stable/10/sys/kern/syscalls.master' | ./mksysnum_freebsd.pl"
|
||||
mktypes="GOARCH=$GOARCH go tool cgo -godefs"
|
||||
;;
|
||||
freebsd_amd64)
|
||||
mkerrors="$mkerrors -m64"
|
||||
mksysnum="curl -s 'http://svn.freebsd.org/base/stable/10/sys/kern/syscalls.master' | ./mksysnum_freebsd.pl"
|
||||
mktypes="GOARCH=$GOARCH go tool cgo -godefs"
|
||||
;;
|
||||
freebsd_arm)
|
||||
mkerrors="$mkerrors"
|
||||
mksyscall="./mksyscall.pl -l32 -arm"
|
||||
mksysnum="curl -s 'http://svn.freebsd.org/base/stable/10/sys/kern/syscalls.master' | ./mksysnum_freebsd.pl"
|
||||
# Let the type of C char be singed for making the bare syscall
|
||||
# API consistent across over platforms.
|
||||
mktypes="GOARCH=$GOARCH go tool cgo -godefs -- -fsigned-char"
|
||||
;;
|
||||
linux_386)
|
||||
mkerrors="$mkerrors -m32"
|
||||
mksyscall="./mksyscall.pl -l32"
|
||||
mksysnum="./mksysnum_linux.pl /usr/include/asm/unistd_32.h"
|
||||
mktypes="GOARCH=$GOARCH go tool cgo -godefs"
|
||||
;;
|
||||
linux_amd64)
|
||||
unistd_h=$(ls -1 /usr/include/asm/unistd_64.h /usr/include/x86_64-linux-gnu/asm/unistd_64.h 2>/dev/null | head -1)
|
||||
if [ "$unistd_h" = "" ]; then
|
||||
echo >&2 cannot find unistd_64.h
|
||||
exit 1
|
||||
fi
|
||||
mkerrors="$mkerrors -m64"
|
||||
mksysnum="./mksysnum_linux.pl $unistd_h"
|
||||
mktypes="GOARCH=$GOARCH go tool cgo -godefs"
|
||||
;;
|
||||
linux_arm)
|
||||
mkerrors="$mkerrors"
|
||||
mksyscall="./mksyscall.pl -l32 -arm"
|
||||
mksysnum="curl -s 'http://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/plain/arch/arm/include/uapi/asm/unistd.h' | ./mksysnum_linux.pl"
|
||||
mktypes="GOARCH=$GOARCH go tool cgo -godefs"
|
||||
;;
|
||||
nacl_386)
|
||||
mkerrors=""
|
||||
mksyscall="./mksyscall.pl -l32 -nacl"
|
||||
mksysnum=""
|
||||
mktypes=""
|
||||
;;
|
||||
nacl_amd64p32)
|
||||
mkerrors=""
|
||||
mksyscall="./mksyscall.pl -nacl"
|
||||
mksysnum=""
|
||||
mktypes=""
|
||||
;;
|
||||
netbsd_386)
|
||||
mkerrors="$mkerrors -m32"
|
||||
mksyscall="./mksyscall.pl -l32 -netbsd"
|
||||
mksysnum="curl -s 'http://cvsweb.netbsd.org/bsdweb.cgi/~checkout~/src/sys/kern/syscalls.master' | ./mksysnum_netbsd.pl"
|
||||
mktypes="GOARCH=$GOARCH go tool cgo -godefs"
|
||||
;;
|
||||
netbsd_amd64)
|
||||
mkerrors="$mkerrors -m64"
|
||||
mksyscall="./mksyscall.pl -netbsd"
|
||||
mksysnum="curl -s 'http://cvsweb.netbsd.org/bsdweb.cgi/~checkout~/src/sys/kern/syscalls.master' | ./mksysnum_netbsd.pl"
|
||||
mktypes="GOARCH=$GOARCH go tool cgo -godefs"
|
||||
;;
|
||||
openbsd_386)
|
||||
mkerrors="$mkerrors -m32"
|
||||
mksyscall="./mksyscall.pl -l32 -openbsd"
|
||||
mksysctl="./mksysctl_openbsd.pl"
|
||||
zsysctl="zsysctl_openbsd.go"
|
||||
mksysnum="curl -s 'http://www.openbsd.org/cgi-bin/cvsweb/~checkout~/src/sys/kern/syscalls.master' | ./mksysnum_openbsd.pl"
|
||||
mktypes="GOARCH=$GOARCH go tool cgo -godefs"
|
||||
;;
|
||||
openbsd_amd64)
|
||||
mkerrors="$mkerrors -m64"
|
||||
mksyscall="./mksyscall.pl -openbsd"
|
||||
mksysctl="./mksysctl_openbsd.pl"
|
||||
zsysctl="zsysctl_openbsd.go"
|
||||
mksysnum="curl -s 'http://www.openbsd.org/cgi-bin/cvsweb/~checkout~/src/sys/kern/syscalls.master' | ./mksysnum_openbsd.pl"
|
||||
mktypes="GOARCH=$GOARCH go tool cgo -godefs"
|
||||
;;
|
||||
plan9_386)
|
||||
mkerrors=
|
||||
mksyscall="./mksyscall.pl -l32 -plan9"
|
||||
mksysnum="./mksysnum_plan9.sh /n/sources/plan9/sys/src/libc/9syscall/sys.h"
|
||||
mktypes="XXX"
|
||||
;;
|
||||
solaris_amd64)
|
||||
mksyscall="./mksyscall_solaris.pl"
|
||||
mkerrors="$mkerrors -m64"
|
||||
mksysnum=
|
||||
mktypes="GOARCH=$GOARCH go tool cgo -godefs"
|
||||
;;
|
||||
windows_*)
|
||||
mksyscall=
|
||||
mkerrors=
|
||||
zerrors=
|
||||
;;
|
||||
*)
|
||||
echo 'unrecognized $GOOS_$GOARCH: ' "$GOOSARCH" 1>&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
(
|
||||
if [ -n "$mkerrors" ]; then echo "$mkerrors |gofmt >$zerrors"; fi
|
||||
case "$GOOS" in
|
||||
windows)
|
||||
echo "GOOS= GOARCH= go build mksyscall_windows.go"
|
||||
echo "./mksyscall_windows syscall_windows.go security_windows.go syscall_$GOOSARCH.go |gofmt >zsyscall_$GOOSARCH.go"
|
||||
echo "rm -f ./mksyscall_windows"
|
||||
;;
|
||||
*)
|
||||
syscall_goos="syscall_$GOOS.go"
|
||||
case "$GOOS" in
|
||||
darwin | dragonfly | freebsd | netbsd | openbsd)
|
||||
syscall_goos="syscall_bsd.go $syscall_goos"
|
||||
;;
|
||||
esac
|
||||
if [ -n "$mksyscall" ]; then echo "$mksyscall $syscall_goos syscall_$GOOSARCH.go |gofmt >zsyscall_$GOOSARCH.go"; fi
|
||||
;;
|
||||
esac
|
||||
if [ -n "$mksysctl" ]; then echo "$mksysctl |gofmt >$zsysctl"; fi
|
||||
if [ -n "$mksysnum" ]; then echo "$mksysnum |gofmt >zsysnum_$GOOSARCH.go"; fi
|
||||
if [ -n "$mktypes" ]; then echo "$mktypes types_$GOOS.go |gofmt >ztypes_$GOOSARCH.go"; fi
|
||||
) | $run
|
||||
@@ -0,0 +1,21 @@
|
||||
:: Copyright 2013 The Go Authors. All rights reserved.
|
||||
:: Use of this source code is governed by a BSD-style
|
||||
:: license that can be found in the LICENSE file.
|
||||
@echo off
|
||||
|
||||
if exist mkall.sh goto dirok
|
||||
echo mkall_windows.bat must be run from src\pkg\syscall directory
|
||||
goto :end
|
||||
:dirok
|
||||
|
||||
if "%1"=="386" goto :paramok
|
||||
if "%1"=="amd64" goto :paramok
|
||||
echo parameters must be 386 or amd64
|
||||
goto :end
|
||||
:paramok
|
||||
|
||||
go build mksyscall_windows.go
|
||||
.\mksyscall_windows syscall_windows.go security_windows.go syscall_windows_%1.go |gofmt >zsyscall_windows_%1.go
|
||||
del mksyscall_windows.exe
|
||||
|
||||
:end
|
||||
Executable
+313
@@ -0,0 +1,313 @@
|
||||
#!/usr/bin/env perl
|
||||
# Copyright 2009 The Go Authors. All rights reserved.
|
||||
# Use of this source code is governed by a BSD-style
|
||||
# license that can be found in the LICENSE file.
|
||||
|
||||
# This program reads a file containing function prototypes
|
||||
# (like syscall_darwin.go) and generates system call bodies.
|
||||
# The prototypes are marked by lines beginning with "//sys"
|
||||
# and read like func declarations if //sys is replaced by func, but:
|
||||
# * The parameter lists must give a name for each argument.
|
||||
# This includes return parameters.
|
||||
# * The parameter lists must give a type for each argument:
|
||||
# the (x, y, z int) shorthand is not allowed.
|
||||
# * If the return parameter is an error number, it must be named errno.
|
||||
|
||||
# A line beginning with //sysnb is like //sys, except that the
|
||||
# goroutine will not be suspended during the execution of the system
|
||||
# call. This must only be used for system calls which can never
|
||||
# block, as otherwise the system call could cause all goroutines to
|
||||
# hang.
|
||||
|
||||
use strict;
|
||||
|
||||
my $cmdline = "mksyscall.pl " . join(' ', @ARGV);
|
||||
my $errors = 0;
|
||||
my $_32bit = "";
|
||||
my $plan9 = 0;
|
||||
my $openbsd = 0;
|
||||
my $netbsd = 0;
|
||||
my $dragonfly = 0;
|
||||
my $nacl = 0;
|
||||
my $arm = 0; # 64-bit value should use (even, odd)-pair
|
||||
|
||||
if($ARGV[0] eq "-b32") {
|
||||
$_32bit = "big-endian";
|
||||
shift;
|
||||
} elsif($ARGV[0] eq "-l32") {
|
||||
$_32bit = "little-endian";
|
||||
shift;
|
||||
}
|
||||
if($ARGV[0] eq "-plan9") {
|
||||
$plan9 = 1;
|
||||
shift;
|
||||
}
|
||||
if($ARGV[0] eq "-openbsd") {
|
||||
$openbsd = 1;
|
||||
shift;
|
||||
}
|
||||
if($ARGV[0] eq "-netbsd") {
|
||||
$netbsd = 1;
|
||||
shift;
|
||||
}
|
||||
if($ARGV[0] eq "-dragonfly") {
|
||||
$dragonfly = 1;
|
||||
shift;
|
||||
}
|
||||
if($ARGV[0] eq "-nacl") {
|
||||
$nacl = 1;
|
||||
shift;
|
||||
}
|
||||
if($ARGV[0] eq "-arm") {
|
||||
$arm = 1;
|
||||
shift;
|
||||
}
|
||||
|
||||
if($ARGV[0] =~ /^-/) {
|
||||
print STDERR "usage: mksyscall.pl [-b32 | -l32] [file ...]\n";
|
||||
exit 1;
|
||||
}
|
||||
|
||||
sub parseparamlist($) {
|
||||
my ($list) = @_;
|
||||
$list =~ s/^\s*//;
|
||||
$list =~ s/\s*$//;
|
||||
if($list eq "") {
|
||||
return ();
|
||||
}
|
||||
return split(/\s*,\s*/, $list);
|
||||
}
|
||||
|
||||
sub parseparam($) {
|
||||
my ($p) = @_;
|
||||
if($p !~ /^(\S*) (\S*)$/) {
|
||||
print STDERR "$ARGV:$.: malformed parameter: $p\n";
|
||||
$errors = 1;
|
||||
return ("xx", "int");
|
||||
}
|
||||
return ($1, $2);
|
||||
}
|
||||
|
||||
my $text = "";
|
||||
while(<>) {
|
||||
chomp;
|
||||
s/\s+/ /g;
|
||||
s/^\s+//;
|
||||
s/\s+$//;
|
||||
my $nonblock = /^\/\/sysnb /;
|
||||
next if !/^\/\/sys / && !$nonblock;
|
||||
|
||||
# Line must be of the form
|
||||
# func Open(path string, mode int, perm int) (fd int, errno error)
|
||||
# Split into name, in params, out params.
|
||||
if(!/^\/\/sys(nb)? (\w+)\(([^()]*)\)\s*(?:\(([^()]+)\))?\s*(?:=\s*((?i)SYS_[A-Z0-9_]+))?$/) {
|
||||
print STDERR "$ARGV:$.: malformed //sys declaration\n";
|
||||
$errors = 1;
|
||||
next;
|
||||
}
|
||||
my ($func, $in, $out, $sysname) = ($2, $3, $4, $5);
|
||||
|
||||
# Split argument lists on comma.
|
||||
my @in = parseparamlist($in);
|
||||
my @out = parseparamlist($out);
|
||||
|
||||
# Try in vain to keep people from editing this file.
|
||||
# The theory is that they jump into the middle of the file
|
||||
# without reading the header.
|
||||
$text .= "// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT\n\n";
|
||||
|
||||
# Go function header.
|
||||
my $out_decl = @out ? sprintf(" (%s)", join(', ', @out)) : "";
|
||||
$text .= sprintf "func %s(%s)%s {\n", $func, join(', ', @in), $out_decl;
|
||||
|
||||
# Check if err return available
|
||||
my $errvar = "";
|
||||
foreach my $p (@out) {
|
||||
my ($name, $type) = parseparam($p);
|
||||
if($type eq "error") {
|
||||
$errvar = $name;
|
||||
last;
|
||||
}
|
||||
}
|
||||
|
||||
# Prepare arguments to Syscall.
|
||||
my @args = ();
|
||||
my $n = 0;
|
||||
foreach my $p (@in) {
|
||||
my ($name, $type) = parseparam($p);
|
||||
if($type =~ /^\*/) {
|
||||
push @args, "uintptr(unsafe.Pointer($name))";
|
||||
} elsif($type eq "string" && $errvar ne "") {
|
||||
$text .= "\tvar _p$n *byte\n";
|
||||
$text .= "\t_p$n, $errvar = BytePtrFromString($name)\n";
|
||||
$text .= "\tif $errvar != nil {\n\t\treturn\n\t}\n";
|
||||
push @args, "uintptr(unsafe.Pointer(_p$n))";
|
||||
$n++;
|
||||
} elsif($type eq "string") {
|
||||
print STDERR "$ARGV:$.: $func uses string arguments, but has no error return\n";
|
||||
$text .= "\tvar _p$n *byte\n";
|
||||
$text .= "\t_p$n, _ = BytePtrFromString($name)\n";
|
||||
push @args, "uintptr(unsafe.Pointer(_p$n))";
|
||||
$n++;
|
||||
} elsif($type =~ /^\[\](.*)/) {
|
||||
# Convert slice into pointer, length.
|
||||
# Have to be careful not to take address of &a[0] if len == 0:
|
||||
# pass dummy pointer in that case.
|
||||
# Used to pass nil, but some OSes or simulators reject write(fd, nil, 0).
|
||||
$text .= "\tvar _p$n unsafe.Pointer\n";
|
||||
$text .= "\tif len($name) > 0 {\n\t\t_p$n = unsafe.Pointer(\&${name}[0])\n\t}";
|
||||
$text .= " else {\n\t\t_p$n = unsafe.Pointer(&_zero)\n\t}";
|
||||
$text .= "\n";
|
||||
push @args, "uintptr(_p$n)", "uintptr(len($name))";
|
||||
$n++;
|
||||
} elsif($type eq "int64" && ($openbsd || $netbsd)) {
|
||||
push @args, "0";
|
||||
if($_32bit eq "big-endian") {
|
||||
push @args, "uintptr($name>>32)", "uintptr($name)";
|
||||
} elsif($_32bit eq "little-endian") {
|
||||
push @args, "uintptr($name)", "uintptr($name>>32)";
|
||||
} else {
|
||||
push @args, "uintptr($name)";
|
||||
}
|
||||
} elsif($type eq "int64" && $dragonfly) {
|
||||
if ($func !~ /^extp(read|write)/i) {
|
||||
push @args, "0";
|
||||
}
|
||||
if($_32bit eq "big-endian") {
|
||||
push @args, "uintptr($name>>32)", "uintptr($name)";
|
||||
} elsif($_32bit eq "little-endian") {
|
||||
push @args, "uintptr($name)", "uintptr($name>>32)";
|
||||
} else {
|
||||
push @args, "uintptr($name)";
|
||||
}
|
||||
} elsif($type eq "int64" && $_32bit ne "") {
|
||||
if(@args % 2 && $arm) {
|
||||
# arm abi specifies 64-bit argument uses
|
||||
# (even, odd) pair
|
||||
push @args, "0"
|
||||
}
|
||||
if($_32bit eq "big-endian") {
|
||||
push @args, "uintptr($name>>32)", "uintptr($name)";
|
||||
} else {
|
||||
push @args, "uintptr($name)", "uintptr($name>>32)";
|
||||
}
|
||||
} else {
|
||||
push @args, "uintptr($name)";
|
||||
}
|
||||
}
|
||||
|
||||
# Determine which form to use; pad args with zeros.
|
||||
my $asm = "Syscall";
|
||||
if ($nonblock) {
|
||||
$asm = "RawSyscall";
|
||||
}
|
||||
if(@args <= 3) {
|
||||
while(@args < 3) {
|
||||
push @args, "0";
|
||||
}
|
||||
} elsif(@args <= 6) {
|
||||
$asm .= "6";
|
||||
while(@args < 6) {
|
||||
push @args, "0";
|
||||
}
|
||||
} elsif(@args <= 9) {
|
||||
$asm .= "9";
|
||||
while(@args < 9) {
|
||||
push @args, "0";
|
||||
}
|
||||
} else {
|
||||
print STDERR "$ARGV:$.: too many arguments to system call\n";
|
||||
}
|
||||
|
||||
# System call number.
|
||||
if($sysname eq "") {
|
||||
$sysname = "SYS_$func";
|
||||
$sysname =~ s/([a-z])([A-Z])/${1}_$2/g; # turn FooBar into Foo_Bar
|
||||
$sysname =~ y/a-z/A-Z/;
|
||||
if($nacl) {
|
||||
$sysname =~ y/A-Z/a-z/;
|
||||
}
|
||||
}
|
||||
|
||||
# Actual call.
|
||||
my $args = join(', ', @args);
|
||||
my $call = "$asm($sysname, $args)";
|
||||
|
||||
# Assign return values.
|
||||
my $body = "";
|
||||
my @ret = ("_", "_", "_");
|
||||
my $do_errno = 0;
|
||||
for(my $i=0; $i<@out; $i++) {
|
||||
my $p = $out[$i];
|
||||
my ($name, $type) = parseparam($p);
|
||||
my $reg = "";
|
||||
if($name eq "err" && !$plan9) {
|
||||
$reg = "e1";
|
||||
$ret[2] = $reg;
|
||||
$do_errno = 1;
|
||||
} elsif($name eq "err" && $plan9) {
|
||||
$ret[0] = "r0";
|
||||
$ret[2] = "e1";
|
||||
next;
|
||||
} else {
|
||||
$reg = sprintf("r%d", $i);
|
||||
$ret[$i] = $reg;
|
||||
}
|
||||
if($type eq "bool") {
|
||||
$reg = "$reg != 0";
|
||||
}
|
||||
if($type eq "int64" && $_32bit ne "") {
|
||||
# 64-bit number in r1:r0 or r0:r1.
|
||||
if($i+2 > @out) {
|
||||
print STDERR "$ARGV:$.: not enough registers for int64 return\n";
|
||||
}
|
||||
if($_32bit eq "big-endian") {
|
||||
$reg = sprintf("int64(r%d)<<32 | int64(r%d)", $i, $i+1);
|
||||
} else {
|
||||
$reg = sprintf("int64(r%d)<<32 | int64(r%d)", $i+1, $i);
|
||||
}
|
||||
$ret[$i] = sprintf("r%d", $i);
|
||||
$ret[$i+1] = sprintf("r%d", $i+1);
|
||||
}
|
||||
if($reg ne "e1" || $plan9) {
|
||||
$body .= "\t$name = $type($reg)\n";
|
||||
}
|
||||
}
|
||||
if ($ret[0] eq "_" && $ret[1] eq "_" && $ret[2] eq "_") {
|
||||
$text .= "\t$call\n";
|
||||
} else {
|
||||
$text .= "\t$ret[0], $ret[1], $ret[2] := $call\n";
|
||||
}
|
||||
$text .= $body;
|
||||
|
||||
if ($plan9 && $ret[2] eq "e1") {
|
||||
$text .= "\tif int32(r0) == -1 {\n";
|
||||
$text .= "\t\terr = e1\n";
|
||||
$text .= "\t}\n";
|
||||
} elsif ($do_errno) {
|
||||
$text .= "\tif e1 != 0 {\n";
|
||||
$text .= "\t\terr = e1\n";
|
||||
$text .= "\t}\n";
|
||||
}
|
||||
$text .= "\treturn\n";
|
||||
$text .= "}\n\n";
|
||||
}
|
||||
|
||||
chomp $text;
|
||||
chomp $text;
|
||||
|
||||
if($errors) {
|
||||
exit 1;
|
||||
}
|
||||
|
||||
print <<EOF;
|
||||
// $cmdline
|
||||
// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
|
||||
|
||||
package syscall
|
||||
|
||||
import "unsafe"
|
||||
|
||||
$text
|
||||
EOF
|
||||
exit 0;
|
||||
@@ -0,0 +1,698 @@
|
||||
// Copyright 2013 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build ignore
|
||||
|
||||
/*
|
||||
mksyscall_windows generates windows system call bodies
|
||||
|
||||
It parses all files specified on command line containing function
|
||||
prototypes (like syscall_windows.go) and prints system call bodies
|
||||
to standard output.
|
||||
|
||||
The prototypes are marked by lines beginning with "//sys" and read
|
||||
like func declarations if //sys is replaced by func, but:
|
||||
|
||||
* The parameter lists must give a name for each argument. This
|
||||
includes return parameters.
|
||||
|
||||
* The parameter lists must give a type for each argument:
|
||||
the (x, y, z int) shorthand is not allowed.
|
||||
|
||||
* If the return parameter is an error number, it must be named err.
|
||||
|
||||
* If go func name needs to be different from it's winapi dll name,
|
||||
the winapi name could be specified at the end, after "=" sign, like
|
||||
//sys LoadLibrary(libname string) (handle uint32, err error) = LoadLibraryA
|
||||
|
||||
* Each function that returns err needs to supply a condition, that
|
||||
return value of winapi will be tested against to detect failure.
|
||||
This would set err to windows "last-error", otherwise it will be nil.
|
||||
The value can be provided at end of //sys declaration, like
|
||||
//sys LoadLibrary(libname string) (handle uint32, err error) [failretval==-1] = LoadLibraryA
|
||||
and is [failretval==0] by default.
|
||||
|
||||
Usage:
|
||||
mksyscall_windows [flags] [path ...]
|
||||
|
||||
The flags are:
|
||||
-trace
|
||||
Generate print statement after every syscall.
|
||||
*/
|
||||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"errors"
|
||||
"flag"
|
||||
"fmt"
|
||||
"go/parser"
|
||||
"go/token"
|
||||
"io"
|
||||
"log"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
"text/template"
|
||||
)
|
||||
|
||||
var PrintTraceFlag = flag.Bool("trace", false, "generate print statement after every syscall")
|
||||
|
||||
func trim(s string) string {
|
||||
return strings.Trim(s, " \t")
|
||||
}
|
||||
|
||||
var packageName string
|
||||
|
||||
func packagename() string {
|
||||
return packageName
|
||||
}
|
||||
|
||||
func syscalldot() string {
|
||||
if packageName == "syscall" {
|
||||
return ""
|
||||
}
|
||||
return "syscall."
|
||||
}
|
||||
|
||||
// Param is function parameter
|
||||
type Param struct {
|
||||
Name string
|
||||
Type string
|
||||
fn *Fn
|
||||
tmpVarIdx int
|
||||
}
|
||||
|
||||
// tmpVar returns temp variable name that will be used to represent p during syscall.
|
||||
func (p *Param) tmpVar() string {
|
||||
if p.tmpVarIdx < 0 {
|
||||
p.tmpVarIdx = p.fn.curTmpVarIdx
|
||||
p.fn.curTmpVarIdx++
|
||||
}
|
||||
return fmt.Sprintf("_p%d", p.tmpVarIdx)
|
||||
}
|
||||
|
||||
// BoolTmpVarCode returns source code for bool temp variable.
|
||||
func (p *Param) BoolTmpVarCode() string {
|
||||
const code = `var %s uint32
|
||||
if %s {
|
||||
%s = 1
|
||||
} else {
|
||||
%s = 0
|
||||
}`
|
||||
tmp := p.tmpVar()
|
||||
return fmt.Sprintf(code, tmp, p.Name, tmp, tmp)
|
||||
}
|
||||
|
||||
// SliceTmpVarCode returns source code for slice temp variable.
|
||||
func (p *Param) SliceTmpVarCode() string {
|
||||
const code = `var %s *%s
|
||||
if len(%s) > 0 {
|
||||
%s = &%s[0]
|
||||
}`
|
||||
tmp := p.tmpVar()
|
||||
return fmt.Sprintf(code, tmp, p.Type[2:], p.Name, tmp, p.Name)
|
||||
}
|
||||
|
||||
// StringTmpVarCode returns source code for string temp variable.
|
||||
func (p *Param) StringTmpVarCode() string {
|
||||
errvar := p.fn.Rets.ErrorVarName()
|
||||
if errvar == "" {
|
||||
errvar = "_"
|
||||
}
|
||||
tmp := p.tmpVar()
|
||||
const code = `var %s %s
|
||||
%s, %s = %s(%s)`
|
||||
s := fmt.Sprintf(code, tmp, p.fn.StrconvType(), tmp, errvar, p.fn.StrconvFunc(), p.Name)
|
||||
if errvar == "-" {
|
||||
return s
|
||||
}
|
||||
const morecode = `
|
||||
if %s != nil {
|
||||
return
|
||||
}`
|
||||
return s + fmt.Sprintf(morecode, errvar)
|
||||
}
|
||||
|
||||
// TmpVarCode returns source code for temp variable.
|
||||
func (p *Param) TmpVarCode() string {
|
||||
switch {
|
||||
case p.Type == "string":
|
||||
return p.StringTmpVarCode()
|
||||
case p.Type == "bool":
|
||||
return p.BoolTmpVarCode()
|
||||
case strings.HasPrefix(p.Type, "[]"):
|
||||
return p.SliceTmpVarCode()
|
||||
default:
|
||||
return ""
|
||||
}
|
||||
}
|
||||
|
||||
// SyscallArgList returns source code fragments representing p parameter
|
||||
// in syscall. Slices are translated into 2 syscall parameters: pointer to
|
||||
// the first element and length.
|
||||
func (p *Param) SyscallArgList() []string {
|
||||
var s string
|
||||
switch {
|
||||
case p.Type[0] == '*':
|
||||
s = fmt.Sprintf("unsafe.Pointer(%s)", p.Name)
|
||||
case p.Type == "string":
|
||||
s = fmt.Sprintf("unsafe.Pointer(%s)", p.tmpVar())
|
||||
case p.Type == "bool":
|
||||
s = p.tmpVar()
|
||||
case strings.HasPrefix(p.Type, "[]"):
|
||||
return []string{
|
||||
fmt.Sprintf("uintptr(unsafe.Pointer(%s))", p.tmpVar()),
|
||||
fmt.Sprintf("uintptr(len(%s))", p.Name),
|
||||
}
|
||||
default:
|
||||
s = p.Name
|
||||
}
|
||||
return []string{fmt.Sprintf("uintptr(%s)", s)}
|
||||
}
|
||||
|
||||
// IsError determines if p parameter is used to return error.
|
||||
func (p *Param) IsError() bool {
|
||||
return p.Name == "err" && p.Type == "error"
|
||||
}
|
||||
|
||||
// join concatenates parameters ps into a string with sep separator.
|
||||
// Each parameter is converted into string by applying fn to it
|
||||
// before conversion.
|
||||
func join(ps []*Param, fn func(*Param) string, sep string) string {
|
||||
if len(ps) == 0 {
|
||||
return ""
|
||||
}
|
||||
a := make([]string, 0)
|
||||
for _, p := range ps {
|
||||
a = append(a, fn(p))
|
||||
}
|
||||
return strings.Join(a, sep)
|
||||
}
|
||||
|
||||
// Rets describes function return parameters.
|
||||
type Rets struct {
|
||||
Name string
|
||||
Type string
|
||||
ReturnsError bool
|
||||
FailCond string
|
||||
}
|
||||
|
||||
// ErrorVarName returns error variable name for r.
|
||||
func (r *Rets) ErrorVarName() string {
|
||||
if r.ReturnsError {
|
||||
return "err"
|
||||
}
|
||||
if r.Type == "error" {
|
||||
return r.Name
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// ToParams converts r into slice of *Param.
|
||||
func (r *Rets) ToParams() []*Param {
|
||||
ps := make([]*Param, 0)
|
||||
if len(r.Name) > 0 {
|
||||
ps = append(ps, &Param{Name: r.Name, Type: r.Type})
|
||||
}
|
||||
if r.ReturnsError {
|
||||
ps = append(ps, &Param{Name: "err", Type: "error"})
|
||||
}
|
||||
return ps
|
||||
}
|
||||
|
||||
// List returns source code of syscall return parameters.
|
||||
func (r *Rets) List() string {
|
||||
s := join(r.ToParams(), func(p *Param) string { return p.Name + " " + p.Type }, ", ")
|
||||
if len(s) > 0 {
|
||||
s = "(" + s + ")"
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
// PrintList returns source code of trace printing part correspondent
|
||||
// to syscall return values.
|
||||
func (r *Rets) PrintList() string {
|
||||
return join(r.ToParams(), func(p *Param) string { return fmt.Sprintf(`"%s=", %s, `, p.Name, p.Name) }, `", ", `)
|
||||
}
|
||||
|
||||
// SetReturnValuesCode returns source code that accepts syscall return values.
|
||||
func (r *Rets) SetReturnValuesCode() string {
|
||||
if r.Name == "" && !r.ReturnsError {
|
||||
return ""
|
||||
}
|
||||
retvar := "r0"
|
||||
if r.Name == "" {
|
||||
retvar = "r1"
|
||||
}
|
||||
errvar := "_"
|
||||
if r.ReturnsError {
|
||||
errvar = "e1"
|
||||
}
|
||||
return fmt.Sprintf("%s, _, %s := ", retvar, errvar)
|
||||
}
|
||||
|
||||
func (r *Rets) useLongHandleErrorCode(retvar string) string {
|
||||
const code = `if %s {
|
||||
if e1 != 0 {
|
||||
err = error(e1)
|
||||
} else {
|
||||
err = %sEINVAL
|
||||
}
|
||||
}`
|
||||
cond := retvar + " == 0"
|
||||
if r.FailCond != "" {
|
||||
cond = strings.Replace(r.FailCond, "failretval", retvar, 1)
|
||||
}
|
||||
return fmt.Sprintf(code, cond, syscalldot())
|
||||
}
|
||||
|
||||
// SetErrorCode returns source code that sets return parameters.
|
||||
func (r *Rets) SetErrorCode() string {
|
||||
const code = `if r0 != 0 {
|
||||
%s = %sErrno(r0)
|
||||
}`
|
||||
if r.Name == "" && !r.ReturnsError {
|
||||
return ""
|
||||
}
|
||||
if r.Name == "" {
|
||||
return r.useLongHandleErrorCode("r1")
|
||||
}
|
||||
if r.Type == "error" {
|
||||
return fmt.Sprintf(code, r.Name, syscalldot())
|
||||
}
|
||||
s := ""
|
||||
switch {
|
||||
case r.Type[0] == '*':
|
||||
s = fmt.Sprintf("%s = (%s)(unsafe.Pointer(r0))", r.Name, r.Type)
|
||||
case r.Type == "bool":
|
||||
s = fmt.Sprintf("%s = r0 != 0", r.Name)
|
||||
default:
|
||||
s = fmt.Sprintf("%s = %s(r0)", r.Name, r.Type)
|
||||
}
|
||||
if !r.ReturnsError {
|
||||
return s
|
||||
}
|
||||
return s + "\n\t" + r.useLongHandleErrorCode(r.Name)
|
||||
}
|
||||
|
||||
// Fn describes syscall function.
|
||||
type Fn struct {
|
||||
Name string
|
||||
Params []*Param
|
||||
Rets *Rets
|
||||
PrintTrace bool
|
||||
dllname string
|
||||
dllfuncname string
|
||||
src string
|
||||
// TODO: get rid of this field and just use parameter index instead
|
||||
curTmpVarIdx int // insure tmp variables have uniq names
|
||||
}
|
||||
|
||||
// extractParams parses s to extract function parameters.
|
||||
func extractParams(s string, f *Fn) ([]*Param, error) {
|
||||
s = trim(s)
|
||||
if s == "" {
|
||||
return nil, nil
|
||||
}
|
||||
a := strings.Split(s, ",")
|
||||
ps := make([]*Param, len(a))
|
||||
for i := range ps {
|
||||
s2 := trim(a[i])
|
||||
b := strings.Split(s2, " ")
|
||||
if len(b) != 2 {
|
||||
b = strings.Split(s2, "\t")
|
||||
if len(b) != 2 {
|
||||
return nil, errors.New("Could not extract function parameter from \"" + s2 + "\"")
|
||||
}
|
||||
}
|
||||
ps[i] = &Param{
|
||||
Name: trim(b[0]),
|
||||
Type: trim(b[1]),
|
||||
fn: f,
|
||||
tmpVarIdx: -1,
|
||||
}
|
||||
}
|
||||
return ps, nil
|
||||
}
|
||||
|
||||
// extractSection extracts text out of string s starting after start
|
||||
// and ending just before end. found return value will indicate success,
|
||||
// and prefix, body and suffix will contain correspondent parts of string s.
|
||||
func extractSection(s string, start, end rune) (prefix, body, suffix string, found bool) {
|
||||
s = trim(s)
|
||||
if strings.HasPrefix(s, string(start)) {
|
||||
// no prefix
|
||||
body = s[1:]
|
||||
} else {
|
||||
a := strings.SplitN(s, string(start), 2)
|
||||
if len(a) != 2 {
|
||||
return "", "", s, false
|
||||
}
|
||||
prefix = a[0]
|
||||
body = a[1]
|
||||
}
|
||||
a := strings.SplitN(body, string(end), 2)
|
||||
if len(a) != 2 {
|
||||
return "", "", "", false
|
||||
}
|
||||
return prefix, a[0], a[1], true
|
||||
}
|
||||
|
||||
// newFn parses string s and return created function Fn.
|
||||
func newFn(s string) (*Fn, error) {
|
||||
s = trim(s)
|
||||
f := &Fn{
|
||||
Rets: &Rets{},
|
||||
src: s,
|
||||
PrintTrace: *PrintTraceFlag,
|
||||
}
|
||||
// function name and args
|
||||
prefix, body, s, found := extractSection(s, '(', ')')
|
||||
if !found || prefix == "" {
|
||||
return nil, errors.New("Could not extract function name and parameters from \"" + f.src + "\"")
|
||||
}
|
||||
f.Name = prefix
|
||||
var err error
|
||||
f.Params, err = extractParams(body, f)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// return values
|
||||
_, body, s, found = extractSection(s, '(', ')')
|
||||
if found {
|
||||
r, err := extractParams(body, f)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
switch len(r) {
|
||||
case 0:
|
||||
case 1:
|
||||
if r[0].IsError() {
|
||||
f.Rets.ReturnsError = true
|
||||
} else {
|
||||
f.Rets.Name = r[0].Name
|
||||
f.Rets.Type = r[0].Type
|
||||
}
|
||||
case 2:
|
||||
if !r[1].IsError() {
|
||||
return nil, errors.New("Only last windows error is allowed as second return value in \"" + f.src + "\"")
|
||||
}
|
||||
f.Rets.ReturnsError = true
|
||||
f.Rets.Name = r[0].Name
|
||||
f.Rets.Type = r[0].Type
|
||||
default:
|
||||
return nil, errors.New("Too many return values in \"" + f.src + "\"")
|
||||
}
|
||||
}
|
||||
// fail condition
|
||||
_, body, s, found = extractSection(s, '[', ']')
|
||||
if found {
|
||||
f.Rets.FailCond = body
|
||||
}
|
||||
// dll and dll function names
|
||||
s = trim(s)
|
||||
if s == "" {
|
||||
return f, nil
|
||||
}
|
||||
if !strings.HasPrefix(s, "=") {
|
||||
return nil, errors.New("Could not extract dll name from \"" + f.src + "\"")
|
||||
}
|
||||
s = trim(s[1:])
|
||||
a := strings.Split(s, ".")
|
||||
switch len(a) {
|
||||
case 1:
|
||||
f.dllfuncname = a[0]
|
||||
case 2:
|
||||
f.dllname = a[0]
|
||||
f.dllfuncname = a[1]
|
||||
default:
|
||||
return nil, errors.New("Could not extract dll name from \"" + f.src + "\"")
|
||||
}
|
||||
return f, nil
|
||||
}
|
||||
|
||||
// DLLName returns DLL name for function f.
|
||||
func (f *Fn) DLLName() string {
|
||||
if f.dllname == "" {
|
||||
return "kernel32"
|
||||
}
|
||||
return f.dllname
|
||||
}
|
||||
|
||||
// DLLName returns DLL function name for function f.
|
||||
func (f *Fn) DLLFuncName() string {
|
||||
if f.dllfuncname == "" {
|
||||
return f.Name
|
||||
}
|
||||
return f.dllfuncname
|
||||
}
|
||||
|
||||
// ParamList returns source code for function f parameters.
|
||||
func (f *Fn) ParamList() string {
|
||||
return join(f.Params, func(p *Param) string { return p.Name + " " + p.Type }, ", ")
|
||||
}
|
||||
|
||||
// ParamPrintList returns source code of trace printing part correspondent
|
||||
// to syscall input parameters.
|
||||
func (f *Fn) ParamPrintList() string {
|
||||
return join(f.Params, func(p *Param) string { return fmt.Sprintf(`"%s=", %s, `, p.Name, p.Name) }, `", ", `)
|
||||
}
|
||||
|
||||
// ParamCount return number of syscall parameters for function f.
|
||||
func (f *Fn) ParamCount() int {
|
||||
n := 0
|
||||
for _, p := range f.Params {
|
||||
n += len(p.SyscallArgList())
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
// SyscallParamCount determines which version of Syscall/Syscall6/Syscall9/...
|
||||
// to use. It returns parameter count for correspondent SyscallX function.
|
||||
func (f *Fn) SyscallParamCount() int {
|
||||
n := f.ParamCount()
|
||||
switch {
|
||||
case n <= 3:
|
||||
return 3
|
||||
case n <= 6:
|
||||
return 6
|
||||
case n <= 9:
|
||||
return 9
|
||||
case n <= 12:
|
||||
return 12
|
||||
case n <= 15:
|
||||
return 15
|
||||
default:
|
||||
panic("too many arguments to system call")
|
||||
}
|
||||
}
|
||||
|
||||
// Syscall determines which SyscallX function to use for function f.
|
||||
func (f *Fn) Syscall() string {
|
||||
c := f.SyscallParamCount()
|
||||
if c == 3 {
|
||||
return syscalldot() + "Syscall"
|
||||
}
|
||||
return syscalldot() + "Syscall" + strconv.Itoa(c)
|
||||
}
|
||||
|
||||
// SyscallParamList returns source code for SyscallX parameters for function f.
|
||||
func (f *Fn) SyscallParamList() string {
|
||||
a := make([]string, 0)
|
||||
for _, p := range f.Params {
|
||||
a = append(a, p.SyscallArgList()...)
|
||||
}
|
||||
for len(a) < f.SyscallParamCount() {
|
||||
a = append(a, "0")
|
||||
}
|
||||
return strings.Join(a, ", ")
|
||||
}
|
||||
|
||||
// IsUTF16 is true, if f is W (utf16) function. It is false
|
||||
// for all A (ascii) functions.
|
||||
func (f *Fn) IsUTF16() bool {
|
||||
s := f.DLLFuncName()
|
||||
return s[len(s)-1] == 'W'
|
||||
}
|
||||
|
||||
// StrconvFunc returns name of Go string to OS string function for f.
|
||||
func (f *Fn) StrconvFunc() string {
|
||||
if f.IsUTF16() {
|
||||
return syscalldot() + "UTF16PtrFromString"
|
||||
}
|
||||
return syscalldot() + "BytePtrFromString"
|
||||
}
|
||||
|
||||
// StrconvType returns Go type name used for OS string for f.
|
||||
func (f *Fn) StrconvType() string {
|
||||
if f.IsUTF16() {
|
||||
return "*uint16"
|
||||
}
|
||||
return "*byte"
|
||||
}
|
||||
|
||||
// Source files and functions.
|
||||
type Source struct {
|
||||
Funcs []*Fn
|
||||
Files []string
|
||||
}
|
||||
|
||||
// ParseFiles parses files listed in fs and extracts all syscall
|
||||
// functions listed in sys comments. It returns source files
|
||||
// and functions collection *Source if successful.
|
||||
func ParseFiles(fs []string) (*Source, error) {
|
||||
src := &Source{
|
||||
Funcs: make([]*Fn, 0),
|
||||
Files: make([]string, 0),
|
||||
}
|
||||
for _, file := range fs {
|
||||
if err := src.ParseFile(file); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return src, nil
|
||||
}
|
||||
|
||||
// DLLs return dll names for a source set src.
|
||||
func (src *Source) DLLs() []string {
|
||||
uniq := make(map[string]bool)
|
||||
r := make([]string, 0)
|
||||
for _, f := range src.Funcs {
|
||||
name := f.DLLName()
|
||||
if _, found := uniq[name]; !found {
|
||||
uniq[name] = true
|
||||
r = append(r, name)
|
||||
}
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
// ParseFile adds adition file path to a source set src.
|
||||
func (src *Source) ParseFile(path string) error {
|
||||
file, err := os.Open(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
s := bufio.NewScanner(file)
|
||||
for s.Scan() {
|
||||
t := trim(s.Text())
|
||||
if len(t) < 7 {
|
||||
continue
|
||||
}
|
||||
if !strings.HasPrefix(t, "//sys") {
|
||||
continue
|
||||
}
|
||||
t = t[5:]
|
||||
if !(t[0] == ' ' || t[0] == '\t') {
|
||||
continue
|
||||
}
|
||||
f, err := newFn(t[1:])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
src.Funcs = append(src.Funcs, f)
|
||||
}
|
||||
if err := s.Err(); err != nil {
|
||||
return err
|
||||
}
|
||||
src.Files = append(src.Files, path)
|
||||
|
||||
// get package name
|
||||
fset := token.NewFileSet()
|
||||
_, err = file.Seek(0, 0)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
pkg, err := parser.ParseFile(fset, "", file, parser.PackageClauseOnly)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
packageName = pkg.Name.Name
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Generate output source file from a source set src.
|
||||
func (src *Source) Generate(w io.Writer) error {
|
||||
funcMap := template.FuncMap{
|
||||
"syscalldot": syscalldot,
|
||||
"packagename": packagename,
|
||||
}
|
||||
t := template.Must(template.New("main").Funcs(funcMap).Parse(srcTemplate))
|
||||
err := t.Execute(w, src)
|
||||
if err != nil {
|
||||
return errors.New("Failed to execute template: " + err.Error())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func usage() {
|
||||
fmt.Fprintf(os.Stderr, "usage: mksyscall_windows [flags] [path ...]\n")
|
||||
flag.PrintDefaults()
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
func main() {
|
||||
flag.Usage = usage
|
||||
flag.Parse()
|
||||
if len(os.Args) <= 1 {
|
||||
fmt.Fprintf(os.Stderr, "no files to parse provided\n")
|
||||
usage()
|
||||
}
|
||||
src, err := ParseFiles(os.Args[1:])
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
if err := src.Generate(os.Stdout); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: use println instead to print in the following template
|
||||
const srcTemplate = `
|
||||
|
||||
{{define "main"}}// go build mksyscall_windows.go && ./mksyscall_windows{{range .Files}} {{.}}{{end}}
|
||||
// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
|
||||
|
||||
package {{packagename}}
|
||||
|
||||
import "unsafe"{{if syscalldot}}
|
||||
import "syscall"{{end}}
|
||||
|
||||
var (
|
||||
{{template "dlls" .}}
|
||||
{{template "funcnames" .}})
|
||||
{{range .Funcs}}{{template "funcbody" .}}{{end}}
|
||||
{{end}}
|
||||
|
||||
{{/* help functions */}}
|
||||
|
||||
{{define "dlls"}}{{range .DLLs}} mod{{.}} = {{syscalldot}}NewLazyDLL("{{.}}.dll")
|
||||
{{end}}{{end}}
|
||||
|
||||
{{define "funcnames"}}{{range .Funcs}} proc{{.DLLFuncName}} = mod{{.DLLName}}.NewProc("{{.DLLFuncName}}")
|
||||
{{end}}{{end}}
|
||||
|
||||
{{define "funcbody"}}
|
||||
func {{.Name}}({{.ParamList}}) {{if .Rets.List}}{{.Rets.List}} {{end}}{
|
||||
{{template "tmpvars" .}} {{template "syscall" .}}
|
||||
{{template "seterror" .}}{{template "printtrace" .}} return
|
||||
}
|
||||
{{end}}
|
||||
|
||||
{{define "tmpvars"}}{{range .Params}}{{if .TmpVarCode}} {{.TmpVarCode}}
|
||||
{{end}}{{end}}{{end}}
|
||||
|
||||
{{define "syscall"}}{{.Rets.SetReturnValuesCode}}{{.Syscall}}(proc{{.DLLFuncName}}.Addr(), {{.ParamCount}}, {{.SyscallParamList}}){{end}}
|
||||
|
||||
{{define "seterror"}}{{if .Rets.SetErrorCode}} {{.Rets.SetErrorCode}}
|
||||
{{end}}{{end}}
|
||||
|
||||
{{define "printtrace"}}{{if .PrintTrace}} print("SYSCALL: {{.Name}}(", {{.ParamPrintList}}") (", {{.Rets.PrintList}}")\n")
|
||||
{{end}}{{end}}
|
||||
|
||||
`
|
||||
@@ -0,0 +1,30 @@
|
||||
// Copyright 2012 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build race
|
||||
|
||||
package syscall
|
||||
|
||||
import (
|
||||
"runtime"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
const raceenabled = true
|
||||
|
||||
func raceAcquire(addr unsafe.Pointer) {
|
||||
runtime.RaceAcquire(addr)
|
||||
}
|
||||
|
||||
func raceReleaseMerge(addr unsafe.Pointer) {
|
||||
runtime.RaceReleaseMerge(addr)
|
||||
}
|
||||
|
||||
func raceReadRange(addr unsafe.Pointer, len int) {
|
||||
runtime.RaceReadRange(addr, len)
|
||||
}
|
||||
|
||||
func raceWriteRange(addr unsafe.Pointer, len int) {
|
||||
runtime.RaceWriteRange(addr, len)
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
// Copyright 2012 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build !race
|
||||
|
||||
package syscall
|
||||
|
||||
import (
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
const raceenabled = false
|
||||
|
||||
func raceAcquire(addr unsafe.Pointer) {
|
||||
}
|
||||
|
||||
func raceReleaseMerge(addr unsafe.Pointer) {
|
||||
}
|
||||
|
||||
func raceReadRange(addr unsafe.Pointer, len int) {
|
||||
}
|
||||
|
||||
func raceWriteRange(addr unsafe.Pointer, len int) {
|
||||
}
|
||||
@@ -0,0 +1,384 @@
|
||||
// Copyright 2012 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package syscall
|
||||
|
||||
import (
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
const (
|
||||
STANDARD_RIGHTS_REQUIRED = 0xf0000
|
||||
STANDARD_RIGHTS_READ = 0x20000
|
||||
STANDARD_RIGHTS_WRITE = 0x20000
|
||||
STANDARD_RIGHTS_EXECUTE = 0x20000
|
||||
STANDARD_RIGHTS_ALL = 0x1F0000
|
||||
)
|
||||
|
||||
const (
|
||||
NameUnknown = 0
|
||||
NameFullyQualifiedDN = 1
|
||||
NameSamCompatible = 2
|
||||
NameDisplay = 3
|
||||
NameUniqueId = 6
|
||||
NameCanonical = 7
|
||||
NameUserPrincipal = 8
|
||||
NameCanonicalEx = 9
|
||||
NameServicePrincipal = 10
|
||||
NameDnsDomain = 12
|
||||
)
|
||||
|
||||
// This function returns 1 byte BOOLEAN rather than the 4 byte BOOL.
|
||||
// http://blogs.msdn.com/b/drnick/archive/2007/12/19/windows-and-upn-format-credentials.aspx
|
||||
//sys TranslateName(accName *uint16, accNameFormat uint32, desiredNameFormat uint32, translatedName *uint16, nSize *uint32) (err error) [failretval&0xff==0] = secur32.TranslateNameW
|
||||
//sys GetUserNameEx(nameFormat uint32, nameBuffre *uint16, nSize *uint32) (err error) [failretval&0xff==0] = secur32.GetUserNameExW
|
||||
|
||||
// TranslateAccountName converts a directory service
|
||||
// object name from one format to another.
|
||||
func TranslateAccountName(username string, from, to uint32, initSize int) (string, error) {
|
||||
u, e := UTF16PtrFromString(username)
|
||||
if e != nil {
|
||||
return "", e
|
||||
}
|
||||
b := make([]uint16, 50)
|
||||
n := uint32(len(b))
|
||||
e = TranslateName(u, from, to, &b[0], &n)
|
||||
if e != nil {
|
||||
if e != ERROR_INSUFFICIENT_BUFFER {
|
||||
return "", e
|
||||
}
|
||||
// make receive buffers of requested size and try again
|
||||
b = make([]uint16, n)
|
||||
e = TranslateName(u, from, to, &b[0], &n)
|
||||
if e != nil {
|
||||
return "", e
|
||||
}
|
||||
}
|
||||
return UTF16ToString(b), nil
|
||||
}
|
||||
|
||||
const (
|
||||
// do not reorder
|
||||
NetSetupUnknownStatus = iota
|
||||
NetSetupUnjoined
|
||||
NetSetupWorkgroupName
|
||||
NetSetupDomainName
|
||||
)
|
||||
|
||||
type UserInfo10 struct {
|
||||
Name *uint16
|
||||
Comment *uint16
|
||||
UsrComment *uint16
|
||||
FullName *uint16
|
||||
}
|
||||
|
||||
//sys NetUserGetInfo(serverName *uint16, userName *uint16, level uint32, buf **byte) (neterr error) = netapi32.NetUserGetInfo
|
||||
//sys NetGetJoinInformation(server *uint16, name **uint16, bufType *uint32) (neterr error) = netapi32.NetGetJoinInformation
|
||||
//sys NetApiBufferFree(buf *byte) (neterr error) = netapi32.NetApiBufferFree
|
||||
|
||||
const (
|
||||
// do not reorder
|
||||
SidTypeUser = 1 + iota
|
||||
SidTypeGroup
|
||||
SidTypeDomain
|
||||
SidTypeAlias
|
||||
SidTypeWellKnownGroup
|
||||
SidTypeDeletedAccount
|
||||
SidTypeInvalid
|
||||
SidTypeUnknown
|
||||
SidTypeComputer
|
||||
SidTypeLabel
|
||||
)
|
||||
|
||||
//sys LookupAccountSid(systemName *uint16, sid *SID, name *uint16, nameLen *uint32, refdDomainName *uint16, refdDomainNameLen *uint32, use *uint32) (err error) = advapi32.LookupAccountSidW
|
||||
//sys LookupAccountName(systemName *uint16, accountName *uint16, sid *SID, sidLen *uint32, refdDomainName *uint16, refdDomainNameLen *uint32, use *uint32) (err error) = advapi32.LookupAccountNameW
|
||||
//sys ConvertSidToStringSid(sid *SID, stringSid **uint16) (err error) = advapi32.ConvertSidToStringSidW
|
||||
//sys ConvertStringSidToSid(stringSid *uint16, sid **SID) (err error) = advapi32.ConvertStringSidToSidW
|
||||
//sys GetLengthSid(sid *SID) (len uint32) = advapi32.GetLengthSid
|
||||
//sys CopySid(destSidLen uint32, destSid *SID, srcSid *SID) (err error) = advapi32.CopySid
|
||||
|
||||
// The security identifier (SID) structure is a variable-length
|
||||
// structure used to uniquely identify users or groups.
|
||||
type SID struct{}
|
||||
|
||||
// StringToSid converts a string-format security identifier
|
||||
// sid into a valid, functional sid.
|
||||
func StringToSid(s string) (*SID, error) {
|
||||
var sid *SID
|
||||
p, e := UTF16PtrFromString(s)
|
||||
if e != nil {
|
||||
return nil, e
|
||||
}
|
||||
e = ConvertStringSidToSid(p, &sid)
|
||||
if e != nil {
|
||||
return nil, e
|
||||
}
|
||||
defer LocalFree((Handle)(unsafe.Pointer(sid)))
|
||||
return sid.Copy()
|
||||
}
|
||||
|
||||
// LookupSID retrieves a security identifier sid for the account
|
||||
// and the name of the domain on which the account was found.
|
||||
// System specify target computer to search.
|
||||
func LookupSID(system, account string) (sid *SID, domain string, accType uint32, err error) {
|
||||
if len(account) == 0 {
|
||||
return nil, "", 0, EINVAL
|
||||
}
|
||||
acc, e := UTF16PtrFromString(account)
|
||||
if e != nil {
|
||||
return nil, "", 0, e
|
||||
}
|
||||
var sys *uint16
|
||||
if len(system) > 0 {
|
||||
sys, e = UTF16PtrFromString(system)
|
||||
if e != nil {
|
||||
return nil, "", 0, e
|
||||
}
|
||||
}
|
||||
db := make([]uint16, 50)
|
||||
dn := uint32(len(db))
|
||||
b := make([]byte, 50)
|
||||
n := uint32(len(b))
|
||||
sid = (*SID)(unsafe.Pointer(&b[0]))
|
||||
e = LookupAccountName(sys, acc, sid, &n, &db[0], &dn, &accType)
|
||||
if e != nil {
|
||||
if e != ERROR_INSUFFICIENT_BUFFER {
|
||||
return nil, "", 0, e
|
||||
}
|
||||
// make receive buffers of requested size and try again
|
||||
b = make([]byte, n)
|
||||
sid = (*SID)(unsafe.Pointer(&b[0]))
|
||||
db = make([]uint16, dn)
|
||||
e = LookupAccountName(sys, acc, sid, &n, &db[0], &dn, &accType)
|
||||
if e != nil {
|
||||
return nil, "", 0, e
|
||||
}
|
||||
}
|
||||
return sid, UTF16ToString(db), accType, nil
|
||||
}
|
||||
|
||||
// String converts sid to a string format
|
||||
// suitable for display, storage, or transmission.
|
||||
func (sid *SID) String() (string, error) {
|
||||
var s *uint16
|
||||
e := ConvertSidToStringSid(sid, &s)
|
||||
if e != nil {
|
||||
return "", e
|
||||
}
|
||||
defer LocalFree((Handle)(unsafe.Pointer(s)))
|
||||
return UTF16ToString((*[256]uint16)(unsafe.Pointer(s))[:]), nil
|
||||
}
|
||||
|
||||
// Len returns the length, in bytes, of a valid security identifier sid.
|
||||
func (sid *SID) Len() int {
|
||||
return int(GetLengthSid(sid))
|
||||
}
|
||||
|
||||
// Copy creates a duplicate of security identifier sid.
|
||||
func (sid *SID) Copy() (*SID, error) {
|
||||
b := make([]byte, sid.Len())
|
||||
sid2 := (*SID)(unsafe.Pointer(&b[0]))
|
||||
e := CopySid(uint32(len(b)), sid2, sid)
|
||||
if e != nil {
|
||||
return nil, e
|
||||
}
|
||||
return sid2, nil
|
||||
}
|
||||
|
||||
// LookupAccount retrieves the name of the account for this sid
|
||||
// and the name of the first domain on which this sid is found.
|
||||
// System specify target computer to search for.
|
||||
func (sid *SID) LookupAccount(system string) (account, domain string, accType uint32, err error) {
|
||||
var sys *uint16
|
||||
if len(system) > 0 {
|
||||
sys, err = UTF16PtrFromString(system)
|
||||
if err != nil {
|
||||
return "", "", 0, err
|
||||
}
|
||||
}
|
||||
b := make([]uint16, 50)
|
||||
n := uint32(len(b))
|
||||
db := make([]uint16, 50)
|
||||
dn := uint32(len(db))
|
||||
e := LookupAccountSid(sys, sid, &b[0], &n, &db[0], &dn, &accType)
|
||||
if e != nil {
|
||||
if e != ERROR_INSUFFICIENT_BUFFER {
|
||||
return "", "", 0, e
|
||||
}
|
||||
// make receive buffers of requested size and try again
|
||||
b = make([]uint16, n)
|
||||
db = make([]uint16, dn)
|
||||
e = LookupAccountSid(nil, sid, &b[0], &n, &db[0], &dn, &accType)
|
||||
if e != nil {
|
||||
return "", "", 0, e
|
||||
}
|
||||
}
|
||||
return UTF16ToString(b), UTF16ToString(db), accType, nil
|
||||
}
|
||||
|
||||
const (
|
||||
// do not reorder
|
||||
TOKEN_ASSIGN_PRIMARY = 1 << iota
|
||||
TOKEN_DUPLICATE
|
||||
TOKEN_IMPERSONATE
|
||||
TOKEN_QUERY
|
||||
TOKEN_QUERY_SOURCE
|
||||
TOKEN_ADJUST_PRIVILEGES
|
||||
TOKEN_ADJUST_GROUPS
|
||||
TOKEN_ADJUST_DEFAULT
|
||||
|
||||
TOKEN_ALL_ACCESS = STANDARD_RIGHTS_REQUIRED |
|
||||
TOKEN_ASSIGN_PRIMARY |
|
||||
TOKEN_DUPLICATE |
|
||||
TOKEN_IMPERSONATE |
|
||||
TOKEN_QUERY |
|
||||
TOKEN_QUERY_SOURCE |
|
||||
TOKEN_ADJUST_PRIVILEGES |
|
||||
TOKEN_ADJUST_GROUPS |
|
||||
TOKEN_ADJUST_DEFAULT
|
||||
TOKEN_READ = STANDARD_RIGHTS_READ | TOKEN_QUERY
|
||||
TOKEN_WRITE = STANDARD_RIGHTS_WRITE |
|
||||
TOKEN_ADJUST_PRIVILEGES |
|
||||
TOKEN_ADJUST_GROUPS |
|
||||
TOKEN_ADJUST_DEFAULT
|
||||
TOKEN_EXECUTE = STANDARD_RIGHTS_EXECUTE
|
||||
)
|
||||
|
||||
const (
|
||||
// do not reorder
|
||||
TokenUser = 1 + iota
|
||||
TokenGroups
|
||||
TokenPrivileges
|
||||
TokenOwner
|
||||
TokenPrimaryGroup
|
||||
TokenDefaultDacl
|
||||
TokenSource
|
||||
TokenType
|
||||
TokenImpersonationLevel
|
||||
TokenStatistics
|
||||
TokenRestrictedSids
|
||||
TokenSessionId
|
||||
TokenGroupsAndPrivileges
|
||||
TokenSessionReference
|
||||
TokenSandBoxInert
|
||||
TokenAuditPolicy
|
||||
TokenOrigin
|
||||
TokenElevationType
|
||||
TokenLinkedToken
|
||||
TokenElevation
|
||||
TokenHasRestrictions
|
||||
TokenAccessInformation
|
||||
TokenVirtualizationAllowed
|
||||
TokenVirtualizationEnabled
|
||||
TokenIntegrityLevel
|
||||
TokenUIAccess
|
||||
TokenMandatoryPolicy
|
||||
TokenLogonSid
|
||||
MaxTokenInfoClass
|
||||
)
|
||||
|
||||
type SIDAndAttributes struct {
|
||||
Sid *SID
|
||||
Attributes uint32
|
||||
}
|
||||
|
||||
type Tokenuser struct {
|
||||
User SIDAndAttributes
|
||||
}
|
||||
|
||||
type Tokenprimarygroup struct {
|
||||
PrimaryGroup *SID
|
||||
}
|
||||
|
||||
//sys OpenProcessToken(h Handle, access uint32, token *Token) (err error) = advapi32.OpenProcessToken
|
||||
//sys GetTokenInformation(t Token, infoClass uint32, info *byte, infoLen uint32, returnedLen *uint32) (err error) = advapi32.GetTokenInformation
|
||||
//sys GetUserProfileDirectory(t Token, dir *uint16, dirLen *uint32) (err error) = userenv.GetUserProfileDirectoryW
|
||||
|
||||
// An access token contains the security information for a logon session.
|
||||
// The system creates an access token when a user logs on, and every
|
||||
// process executed on behalf of the user has a copy of the token.
|
||||
// The token identifies the user, the user's groups, and the user's
|
||||
// privileges. The system uses the token to control access to securable
|
||||
// objects and to control the ability of the user to perform various
|
||||
// system-related operations on the local computer.
|
||||
type Token Handle
|
||||
|
||||
// OpenCurrentProcessToken opens the access token
|
||||
// associated with current process.
|
||||
func OpenCurrentProcessToken() (Token, error) {
|
||||
p, e := GetCurrentProcess()
|
||||
if e != nil {
|
||||
return 0, e
|
||||
}
|
||||
var t Token
|
||||
e = OpenProcessToken(p, TOKEN_QUERY, &t)
|
||||
if e != nil {
|
||||
return 0, e
|
||||
}
|
||||
return t, nil
|
||||
}
|
||||
|
||||
// Close releases access to access token.
|
||||
func (t Token) Close() error {
|
||||
return CloseHandle(Handle(t))
|
||||
}
|
||||
|
||||
// getInfo retrieves a specified type of information about an access token.
|
||||
func (t Token) getInfo(class uint32, initSize int) (unsafe.Pointer, error) {
|
||||
b := make([]byte, initSize)
|
||||
var n uint32
|
||||
e := GetTokenInformation(t, class, &b[0], uint32(len(b)), &n)
|
||||
if e != nil {
|
||||
if e != ERROR_INSUFFICIENT_BUFFER {
|
||||
return nil, e
|
||||
}
|
||||
// make receive buffers of requested size and try again
|
||||
b = make([]byte, n)
|
||||
e = GetTokenInformation(t, class, &b[0], uint32(len(b)), &n)
|
||||
if e != nil {
|
||||
return nil, e
|
||||
}
|
||||
}
|
||||
return unsafe.Pointer(&b[0]), nil
|
||||
}
|
||||
|
||||
// GetTokenUser retrieves access token t user account information.
|
||||
func (t Token) GetTokenUser() (*Tokenuser, error) {
|
||||
i, e := t.getInfo(TokenUser, 50)
|
||||
if e != nil {
|
||||
return nil, e
|
||||
}
|
||||
return (*Tokenuser)(i), nil
|
||||
}
|
||||
|
||||
// GetTokenPrimaryGroup retrieves access token t primary group information.
|
||||
// A pointer to a SID structure representing a group that will become
|
||||
// the primary group of any objects created by a process using this access token.
|
||||
func (t Token) GetTokenPrimaryGroup() (*Tokenprimarygroup, error) {
|
||||
i, e := t.getInfo(TokenPrimaryGroup, 50)
|
||||
if e != nil {
|
||||
return nil, e
|
||||
}
|
||||
return (*Tokenprimarygroup)(i), nil
|
||||
}
|
||||
|
||||
// GetUserProfileDirectory retrieves path to the
|
||||
// root directory of the access token t user's profile.
|
||||
func (t Token) GetUserProfileDirectory() (string, error) {
|
||||
b := make([]uint16, 100)
|
||||
n := uint32(len(b))
|
||||
e := GetUserProfileDirectory(t, &b[0], &n)
|
||||
if e != nil {
|
||||
if e != ERROR_INSUFFICIENT_BUFFER {
|
||||
return "", e
|
||||
}
|
||||
// make receive buffers of requested size and try again
|
||||
b = make([]uint16, n)
|
||||
e = GetUserProfileDirectory(t, &b[0], &n)
|
||||
if e != nil {
|
||||
return "", e
|
||||
}
|
||||
}
|
||||
return UTF16ToString(b), nil
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
// Copyright 2009 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package syscall
|
||||
|
||||
func itoa(val int) string { // do it here rather than with fmt to avoid dependency
|
||||
if val < 0 {
|
||||
return "-" + itoa(-val)
|
||||
}
|
||||
var buf [32]byte // big enough for int64
|
||||
i := len(buf) - 1
|
||||
for val >= 10 {
|
||||
buf[i] = byte(val%10 + '0')
|
||||
i--
|
||||
val /= 10
|
||||
}
|
||||
buf[i] = byte(val + '0')
|
||||
return string(buf[i:])
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
// Copyright 2009 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Package syscall contains an interface to the low-level operating system
|
||||
// primitives. The details vary depending on the underlying system, and
|
||||
// by default, godoc will display the syscall documentation for the current
|
||||
// system. If you want godoc to display syscall documentation for another
|
||||
// system, set $GOOS and $GOARCH to the desired system. For example, if
|
||||
// you want to view documentation for freebsd/arm on linux/amd64, set $GOOS
|
||||
// to freebsd and $GOARCH to arm.
|
||||
// The primary use of syscall is inside other packages that provide a more
|
||||
// portable interface to the system, such as "os", "time" and "net". Use
|
||||
// those packages rather than this one if you can.
|
||||
// For details of the functions and data types in this package consult
|
||||
// the manuals for the appropriate operating system.
|
||||
// These calls return err == nil to indicate success; otherwise
|
||||
// err is an operating system error describing the failure.
|
||||
// On most systems, that error has type syscall.Errno.
|
||||
package syscall
|
||||
|
||||
// StringByteSlice is deprecated. Use ByteSliceFromString instead.
|
||||
// If s contains a NUL byte this function panics instead of
|
||||
// returning an error.
|
||||
func StringByteSlice(s string) []byte {
|
||||
a, err := ByteSliceFromString(s)
|
||||
if err != nil {
|
||||
panic("syscall: string with NUL passed to StringByteSlice")
|
||||
}
|
||||
return a
|
||||
}
|
||||
|
||||
// ByteSliceFromString returns a NUL-terminated slice of bytes
|
||||
// containing the text of s. If s contains a NUL byte at any
|
||||
// location, it returns (nil, EINVAL).
|
||||
func ByteSliceFromString(s string) ([]byte, error) {
|
||||
for i := 0; i < len(s); i++ {
|
||||
if s[i] == 0 {
|
||||
return nil, EINVAL
|
||||
}
|
||||
}
|
||||
a := make([]byte, len(s)+1)
|
||||
copy(a, s)
|
||||
return a, nil
|
||||
}
|
||||
|
||||
// StringBytePtr is deprecated. Use BytePtrFromString instead.
|
||||
// If s contains a NUL byte this function panics instead of
|
||||
// returning an error.
|
||||
func StringBytePtr(s string) *byte { return &StringByteSlice(s)[0] }
|
||||
|
||||
// BytePtrFromString returns a pointer to a NUL-terminated array of
|
||||
// bytes containing the text of s. If s contains a NUL byte at any
|
||||
// location, it returns (nil, EINVAL).
|
||||
func BytePtrFromString(s string) (*byte, error) {
|
||||
a, err := ByteSliceFromString(s)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &a[0], nil
|
||||
}
|
||||
|
||||
// Single-word zero for use when we need a valid pointer to 0 bytes.
|
||||
// See mksyscall.pl.
|
||||
var _zero uintptr
|
||||
|
||||
func (ts *Timespec) Unix() (sec int64, nsec int64) {
|
||||
return int64(ts.Sec), int64(ts.Nsec)
|
||||
}
|
||||
|
||||
func (tv *Timeval) Unix() (sec int64, nsec int64) {
|
||||
return int64(tv.Sec), int64(tv.Usec) * 1000
|
||||
}
|
||||
|
||||
func (ts *Timespec) Nano() int64 {
|
||||
return int64(ts.Sec)*1e9 + int64(ts.Nsec)
|
||||
}
|
||||
|
||||
func (tv *Timeval) Nano() int64 {
|
||||
return int64(tv.Sec)*1e9 + int64(tv.Usec)*1000
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
// Copyright 2013 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package syscall_test
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func testSetGetenv(t *testing.T, key, value string) {
|
||||
err := syscall.Setenv(key, value)
|
||||
if err != nil {
|
||||
t.Fatalf("Setenv failed to set %q: %v", value, err)
|
||||
}
|
||||
newvalue, found := syscall.Getenv(key)
|
||||
if !found {
|
||||
t.Fatalf("Getenv failed to find %v variable (want value %q)", key, value)
|
||||
}
|
||||
if newvalue != value {
|
||||
t.Fatalf("Getenv(%v) = %q; want %q", key, newvalue, value)
|
||||
}
|
||||
}
|
||||
|
||||
func TestEnv(t *testing.T) {
|
||||
testSetGetenv(t, "TESTENV", "AVALUE")
|
||||
// make sure TESTENV gets set to "", not deleted
|
||||
testSetGetenv(t, "TESTENV", "")
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,5 @@
|
||||
// Copyright 2009 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package syscall
|
||||
@@ -0,0 +1,5 @@
|
||||
// Copyright 2009 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package syscall
|
||||
@@ -0,0 +1,72 @@
|
||||
// Copyright 2012 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package syscall_test
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"syscall"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestWin32finddata(t *testing.T) {
|
||||
dir, err := ioutil.TempDir("", "go-build")
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create temp directory: %v", err)
|
||||
}
|
||||
defer os.RemoveAll(dir)
|
||||
|
||||
path := filepath.Join(dir, "long_name.and_extension")
|
||||
f, err := os.Create(path)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create %v: %v", path, err)
|
||||
}
|
||||
f.Close()
|
||||
|
||||
type X struct {
|
||||
fd syscall.Win32finddata
|
||||
got byte
|
||||
pad [10]byte // to protect ourselves
|
||||
|
||||
}
|
||||
var want byte = 2 // it is unlikely to have this character in the filename
|
||||
x := X{got: want}
|
||||
|
||||
pathp, _ := syscall.UTF16PtrFromString(path)
|
||||
h, err := syscall.FindFirstFile(pathp, &(x.fd))
|
||||
if err != nil {
|
||||
t.Fatalf("FindFirstFile failed: %v", err)
|
||||
}
|
||||
err = syscall.FindClose(h)
|
||||
if err != nil {
|
||||
t.Fatalf("FindClose failed: %v", err)
|
||||
}
|
||||
|
||||
if x.got != want {
|
||||
t.Fatalf("memory corruption: want=%d got=%d", want, x.got)
|
||||
}
|
||||
}
|
||||
|
||||
func abort(funcname string, err error) {
|
||||
panic(funcname + " failed: " + err.Error())
|
||||
}
|
||||
|
||||
func ExampleLoadLibrary() {
|
||||
h, err := syscall.LoadLibrary("kernel32.dll")
|
||||
if err != nil {
|
||||
abort("LoadLibrary", err)
|
||||
}
|
||||
defer syscall.FreeLibrary(h)
|
||||
proc, err := syscall.GetProcAddress(h, "GetVersion")
|
||||
if err != nil {
|
||||
abort("GetProcAddress", err)
|
||||
}
|
||||
r, _, _ := syscall.Syscall(uintptr(proc), 0, 0, 0, 0)
|
||||
major := byte(r)
|
||||
minor := uint8(r >> 8)
|
||||
build := uint16(r >> 16)
|
||||
print("windows version ", major, ".", minor, " (Build ", build, ")\n")
|
||||
}
|
||||
@@ -0,0 +1,283 @@
|
||||
// mkerrors_windows.sh -m32
|
||||
// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
|
||||
|
||||
package syscall
|
||||
|
||||
// Go names for Windows errors.
|
||||
const (
|
||||
ENOENT Errno = ERROR_FILE_NOT_FOUND
|
||||
ENOTDIR Errno = ERROR_PATH_NOT_FOUND
|
||||
)
|
||||
|
||||
// Windows reserves errors >= 1<<29 for application use.
|
||||
const APPLICATION_ERROR = 1 << 29
|
||||
|
||||
// Invented values to support what package os and others expects.
|
||||
const (
|
||||
E2BIG Errno = APPLICATION_ERROR + iota
|
||||
EACCES
|
||||
EADDRINUSE
|
||||
EADDRNOTAVAIL
|
||||
EADV
|
||||
EAFNOSUPPORT
|
||||
EAGAIN
|
||||
EALREADY
|
||||
EBADE
|
||||
EBADF
|
||||
EBADFD
|
||||
EBADMSG
|
||||
EBADR
|
||||
EBADRQC
|
||||
EBADSLT
|
||||
EBFONT
|
||||
EBUSY
|
||||
ECANCELED
|
||||
ECHILD
|
||||
ECHRNG
|
||||
ECOMM
|
||||
ECONNABORTED
|
||||
ECONNREFUSED
|
||||
ECONNRESET
|
||||
EDEADLK
|
||||
EDEADLOCK
|
||||
EDESTADDRREQ
|
||||
EDOM
|
||||
EDOTDOT
|
||||
EDQUOT
|
||||
EEXIST
|
||||
EFAULT
|
||||
EFBIG
|
||||
EHOSTDOWN
|
||||
EHOSTUNREACH
|
||||
EIDRM
|
||||
EILSEQ
|
||||
EINPROGRESS
|
||||
EINTR
|
||||
EINVAL
|
||||
EIO
|
||||
EISCONN
|
||||
EISDIR
|
||||
EISNAM
|
||||
EKEYEXPIRED
|
||||
EKEYREJECTED
|
||||
EKEYREVOKED
|
||||
EL2HLT
|
||||
EL2NSYNC
|
||||
EL3HLT
|
||||
EL3RST
|
||||
ELIBACC
|
||||
ELIBBAD
|
||||
ELIBEXEC
|
||||
ELIBMAX
|
||||
ELIBSCN
|
||||
ELNRNG
|
||||
ELOOP
|
||||
EMEDIUMTYPE
|
||||
EMFILE
|
||||
EMLINK
|
||||
EMSGSIZE
|
||||
EMULTIHOP
|
||||
ENAMETOOLONG
|
||||
ENAVAIL
|
||||
ENETDOWN
|
||||
ENETRESET
|
||||
ENETUNREACH
|
||||
ENFILE
|
||||
ENOANO
|
||||
ENOBUFS
|
||||
ENOCSI
|
||||
ENODATA
|
||||
ENODEV
|
||||
ENOEXEC
|
||||
ENOKEY
|
||||
ENOLCK
|
||||
ENOLINK
|
||||
ENOMEDIUM
|
||||
ENOMEM
|
||||
ENOMSG
|
||||
ENONET
|
||||
ENOPKG
|
||||
ENOPROTOOPT
|
||||
ENOSPC
|
||||
ENOSR
|
||||
ENOSTR
|
||||
ENOSYS
|
||||
ENOTBLK
|
||||
ENOTCONN
|
||||
ENOTEMPTY
|
||||
ENOTNAM
|
||||
ENOTRECOVERABLE
|
||||
ENOTSOCK
|
||||
ENOTSUP
|
||||
ENOTTY
|
||||
ENOTUNIQ
|
||||
ENXIO
|
||||
EOPNOTSUPP
|
||||
EOVERFLOW
|
||||
EOWNERDEAD
|
||||
EPERM
|
||||
EPFNOSUPPORT
|
||||
EPIPE
|
||||
EPROTO
|
||||
EPROTONOSUPPORT
|
||||
EPROTOTYPE
|
||||
ERANGE
|
||||
EREMCHG
|
||||
EREMOTE
|
||||
EREMOTEIO
|
||||
ERESTART
|
||||
EROFS
|
||||
ESHUTDOWN
|
||||
ESOCKTNOSUPPORT
|
||||
ESPIPE
|
||||
ESRCH
|
||||
ESRMNT
|
||||
ESTALE
|
||||
ESTRPIPE
|
||||
ETIME
|
||||
ETIMEDOUT
|
||||
ETOOMANYREFS
|
||||
ETXTBSY
|
||||
EUCLEAN
|
||||
EUNATCH
|
||||
EUSERS
|
||||
EWOULDBLOCK
|
||||
EXDEV
|
||||
EXFULL
|
||||
EWINDOWS
|
||||
)
|
||||
|
||||
// Error strings for invented errors
|
||||
var errors = [...]string{
|
||||
E2BIG - APPLICATION_ERROR: "argument list too long",
|
||||
EACCES - APPLICATION_ERROR: "permission denied",
|
||||
EADDRINUSE - APPLICATION_ERROR: "address already in use",
|
||||
EADDRNOTAVAIL - APPLICATION_ERROR: "cannot assign requested address",
|
||||
EADV - APPLICATION_ERROR: "advertise error",
|
||||
EAFNOSUPPORT - APPLICATION_ERROR: "address family not supported by protocol",
|
||||
EAGAIN - APPLICATION_ERROR: "resource temporarily unavailable",
|
||||
EALREADY - APPLICATION_ERROR: "operation already in progress",
|
||||
EBADE - APPLICATION_ERROR: "invalid exchange",
|
||||
EBADF - APPLICATION_ERROR: "bad file descriptor",
|
||||
EBADFD - APPLICATION_ERROR: "file descriptor in bad state",
|
||||
EBADMSG - APPLICATION_ERROR: "bad message",
|
||||
EBADR - APPLICATION_ERROR: "invalid request descriptor",
|
||||
EBADRQC - APPLICATION_ERROR: "invalid request code",
|
||||
EBADSLT - APPLICATION_ERROR: "invalid slot",
|
||||
EBFONT - APPLICATION_ERROR: "bad font file format",
|
||||
EBUSY - APPLICATION_ERROR: "device or resource busy",
|
||||
ECANCELED - APPLICATION_ERROR: "operation canceled",
|
||||
ECHILD - APPLICATION_ERROR: "no child processes",
|
||||
ECHRNG - APPLICATION_ERROR: "channel number out of range",
|
||||
ECOMM - APPLICATION_ERROR: "communication error on send",
|
||||
ECONNABORTED - APPLICATION_ERROR: "software caused connection abort",
|
||||
ECONNREFUSED - APPLICATION_ERROR: "connection refused",
|
||||
ECONNRESET - APPLICATION_ERROR: "connection reset by peer",
|
||||
EDEADLK - APPLICATION_ERROR: "resource deadlock avoided",
|
||||
EDEADLOCK - APPLICATION_ERROR: "resource deadlock avoided",
|
||||
EDESTADDRREQ - APPLICATION_ERROR: "destination address required",
|
||||
EDOM - APPLICATION_ERROR: "numerical argument out of domain",
|
||||
EDOTDOT - APPLICATION_ERROR: "RFS specific error",
|
||||
EDQUOT - APPLICATION_ERROR: "disk quota exceeded",
|
||||
EEXIST - APPLICATION_ERROR: "file exists",
|
||||
EFAULT - APPLICATION_ERROR: "bad address",
|
||||
EFBIG - APPLICATION_ERROR: "file too large",
|
||||
EHOSTDOWN - APPLICATION_ERROR: "host is down",
|
||||
EHOSTUNREACH - APPLICATION_ERROR: "no route to host",
|
||||
EIDRM - APPLICATION_ERROR: "identifier removed",
|
||||
EILSEQ - APPLICATION_ERROR: "invalid or incomplete multibyte or wide character",
|
||||
EINPROGRESS - APPLICATION_ERROR: "operation now in progress",
|
||||
EINTR - APPLICATION_ERROR: "interrupted system call",
|
||||
EINVAL - APPLICATION_ERROR: "invalid argument",
|
||||
EIO - APPLICATION_ERROR: "input/output error",
|
||||
EISCONN - APPLICATION_ERROR: "transport endpoint is already connected",
|
||||
EISDIR - APPLICATION_ERROR: "is a directory",
|
||||
EISNAM - APPLICATION_ERROR: "is a named type file",
|
||||
EKEYEXPIRED - APPLICATION_ERROR: "key has expired",
|
||||
EKEYREJECTED - APPLICATION_ERROR: "key was rejected by service",
|
||||
EKEYREVOKED - APPLICATION_ERROR: "key has been revoked",
|
||||
EL2HLT - APPLICATION_ERROR: "level 2 halted",
|
||||
EL2NSYNC - APPLICATION_ERROR: "level 2 not synchronized",
|
||||
EL3HLT - APPLICATION_ERROR: "level 3 halted",
|
||||
EL3RST - APPLICATION_ERROR: "level 3 reset",
|
||||
ELIBACC - APPLICATION_ERROR: "can not access a needed shared library",
|
||||
ELIBBAD - APPLICATION_ERROR: "accessing a corrupted shared library",
|
||||
ELIBEXEC - APPLICATION_ERROR: "cannot exec a shared library directly",
|
||||
ELIBMAX - APPLICATION_ERROR: "attempting to link in too many shared libraries",
|
||||
ELIBSCN - APPLICATION_ERROR: ".lib section in a.out corrupted",
|
||||
ELNRNG - APPLICATION_ERROR: "link number out of range",
|
||||
ELOOP - APPLICATION_ERROR: "too many levels of symbolic links",
|
||||
EMEDIUMTYPE - APPLICATION_ERROR: "wrong medium type",
|
||||
EMFILE - APPLICATION_ERROR: "too many open files",
|
||||
EMLINK - APPLICATION_ERROR: "too many links",
|
||||
EMSGSIZE - APPLICATION_ERROR: "message too long",
|
||||
EMULTIHOP - APPLICATION_ERROR: "multihop attempted",
|
||||
ENAMETOOLONG - APPLICATION_ERROR: "file name too long",
|
||||
ENAVAIL - APPLICATION_ERROR: "no XENIX semaphores available",
|
||||
ENETDOWN - APPLICATION_ERROR: "network is down",
|
||||
ENETRESET - APPLICATION_ERROR: "network dropped connection on reset",
|
||||
ENETUNREACH - APPLICATION_ERROR: "network is unreachable",
|
||||
ENFILE - APPLICATION_ERROR: "too many open files in system",
|
||||
ENOANO - APPLICATION_ERROR: "no anode",
|
||||
ENOBUFS - APPLICATION_ERROR: "no buffer space available",
|
||||
ENOCSI - APPLICATION_ERROR: "no CSI structure available",
|
||||
ENODATA - APPLICATION_ERROR: "no data available",
|
||||
ENODEV - APPLICATION_ERROR: "no such device",
|
||||
ENOEXEC - APPLICATION_ERROR: "exec format error",
|
||||
ENOKEY - APPLICATION_ERROR: "required key not available",
|
||||
ENOLCK - APPLICATION_ERROR: "no locks available",
|
||||
ENOLINK - APPLICATION_ERROR: "link has been severed",
|
||||
ENOMEDIUM - APPLICATION_ERROR: "no medium found",
|
||||
ENOMEM - APPLICATION_ERROR: "cannot allocate memory",
|
||||
ENOMSG - APPLICATION_ERROR: "no message of desired type",
|
||||
ENONET - APPLICATION_ERROR: "machine is not on the network",
|
||||
ENOPKG - APPLICATION_ERROR: "package not installed",
|
||||
ENOPROTOOPT - APPLICATION_ERROR: "protocol not available",
|
||||
ENOSPC - APPLICATION_ERROR: "no space left on device",
|
||||
ENOSR - APPLICATION_ERROR: "out of streams resources",
|
||||
ENOSTR - APPLICATION_ERROR: "device not a stream",
|
||||
ENOSYS - APPLICATION_ERROR: "function not implemented",
|
||||
ENOTBLK - APPLICATION_ERROR: "block device required",
|
||||
ENOTCONN - APPLICATION_ERROR: "transport endpoint is not connected",
|
||||
ENOTEMPTY - APPLICATION_ERROR: "directory not empty",
|
||||
ENOTNAM - APPLICATION_ERROR: "not a XENIX named type file",
|
||||
ENOTRECOVERABLE - APPLICATION_ERROR: "state not recoverable",
|
||||
ENOTSOCK - APPLICATION_ERROR: "socket operation on non-socket",
|
||||
ENOTSUP - APPLICATION_ERROR: "operation not supported",
|
||||
ENOTTY - APPLICATION_ERROR: "inappropriate ioctl for device",
|
||||
ENOTUNIQ - APPLICATION_ERROR: "name not unique on network",
|
||||
ENXIO - APPLICATION_ERROR: "no such device or address",
|
||||
EOPNOTSUPP - APPLICATION_ERROR: "operation not supported",
|
||||
EOVERFLOW - APPLICATION_ERROR: "value too large for defined data type",
|
||||
EOWNERDEAD - APPLICATION_ERROR: "owner died",
|
||||
EPERM - APPLICATION_ERROR: "operation not permitted",
|
||||
EPFNOSUPPORT - APPLICATION_ERROR: "protocol family not supported",
|
||||
EPIPE - APPLICATION_ERROR: "broken pipe",
|
||||
EPROTO - APPLICATION_ERROR: "protocol error",
|
||||
EPROTONOSUPPORT - APPLICATION_ERROR: "protocol not supported",
|
||||
EPROTOTYPE - APPLICATION_ERROR: "protocol wrong type for socket",
|
||||
ERANGE - APPLICATION_ERROR: "numerical result out of range",
|
||||
EREMCHG - APPLICATION_ERROR: "remote address changed",
|
||||
EREMOTE - APPLICATION_ERROR: "object is remote",
|
||||
EREMOTEIO - APPLICATION_ERROR: "remote I/O error",
|
||||
ERESTART - APPLICATION_ERROR: "interrupted system call should be restarted",
|
||||
EROFS - APPLICATION_ERROR: "read-only file system",
|
||||
ESHUTDOWN - APPLICATION_ERROR: "cannot send after transport endpoint shutdown",
|
||||
ESOCKTNOSUPPORT - APPLICATION_ERROR: "socket type not supported",
|
||||
ESPIPE - APPLICATION_ERROR: "illegal seek",
|
||||
ESRCH - APPLICATION_ERROR: "no such process",
|
||||
ESRMNT - APPLICATION_ERROR: "srmount error",
|
||||
ESTALE - APPLICATION_ERROR: "stale NFS file handle",
|
||||
ESTRPIPE - APPLICATION_ERROR: "streams pipe error",
|
||||
ETIME - APPLICATION_ERROR: "timer expired",
|
||||
ETIMEDOUT - APPLICATION_ERROR: "connection timed out",
|
||||
ETOOMANYREFS - APPLICATION_ERROR: "too many references: cannot splice",
|
||||
ETXTBSY - APPLICATION_ERROR: "text file busy",
|
||||
EUCLEAN - APPLICATION_ERROR: "structure needs cleaning",
|
||||
EUNATCH - APPLICATION_ERROR: "protocol driver not attached",
|
||||
EUSERS - APPLICATION_ERROR: "too many users",
|
||||
EWOULDBLOCK - APPLICATION_ERROR: "resource temporarily unavailable",
|
||||
EXDEV - APPLICATION_ERROR: "invalid cross-device link",
|
||||
EXFULL - APPLICATION_ERROR: "exchange full",
|
||||
EWINDOWS - APPLICATION_ERROR: "not supported by windows",
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
// Copyright 2011 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package syscall
|
||||
@@ -0,0 +1,5 @@
|
||||
// Copyright 2011 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package syscall
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,3 @@
|
||||
// nothing to see here
|
||||
|
||||
package syscall
|
||||
@@ -0,0 +1,3 @@
|
||||
// nothing to see here
|
||||
|
||||
package syscall
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,22 @@
|
||||
// Copyright 2011 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package syscall
|
||||
|
||||
type WSAData struct {
|
||||
Version uint16
|
||||
HighVersion uint16
|
||||
Description [WSADESCRIPTION_LEN + 1]byte
|
||||
SystemStatus [WSASYS_STATUS_LEN + 1]byte
|
||||
MaxSockets uint16
|
||||
MaxUdpDg uint16
|
||||
VendorInfo *byte
|
||||
}
|
||||
|
||||
type Servent struct {
|
||||
Name *byte
|
||||
Aliases **byte
|
||||
Port uint16
|
||||
Proto *byte
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
// Copyright 2011 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package syscall
|
||||
|
||||
type WSAData struct {
|
||||
Version uint16
|
||||
HighVersion uint16
|
||||
MaxSockets uint16
|
||||
MaxUdpDg uint16
|
||||
VendorInfo *byte
|
||||
Description [WSADESCRIPTION_LEN + 1]byte
|
||||
SystemStatus [WSASYS_STATUS_LEN + 1]byte
|
||||
}
|
||||
|
||||
type Servent struct {
|
||||
Name *byte
|
||||
Aliases **byte
|
||||
Proto *byte
|
||||
Port uint16
|
||||
}
|
||||
Reference in New Issue
Block a user