Add vendoring of golang.org/x/sys/windows
parent
6bbd2847e9
commit
90bb7678d4
|
@ -0,0 +1,13 @@
|
||||||
|
// 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
|
||||||
|
//
|
||||||
|
|
||||||
|
TEXT ·getprocaddress(SB), 7, $0-8
|
||||||
|
JMP syscall·getprocaddress(SB)
|
||||||
|
|
||||||
|
TEXT ·loadlibrary(SB), 7, $0-4
|
||||||
|
JMP syscall·loadlibrary(SB)
|
|
@ -0,0 +1,13 @@
|
||||||
|
// 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
|
||||||
|
//
|
||||||
|
|
||||||
|
TEXT ·getprocaddress(SB), 7, $0-32
|
||||||
|
JMP syscall·getprocaddress(SB)
|
||||||
|
|
||||||
|
TEXT ·loadlibrary(SB), 7, $0-8
|
||||||
|
JMP syscall·loadlibrary(SB)
|
|
@ -0,0 +1,378 @@
|
||||||
|
// 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 windows
|
||||||
|
|
||||||
|
import (
|
||||||
|
"sync"
|
||||||
|
"sync/atomic"
|
||||||
|
"syscall"
|
||||||
|
"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; we provide jumps to them in our assembly file.
|
||||||
|
func loadlibrary(filename *uint16) (handle uintptr, err syscall.Errno)
|
||||||
|
func getprocaddress(handle uintptr, procname *uint8) (proc uintptr, err syscall.Errno)
|
||||||
|
|
||||||
|
// A DLL implements access to a single DLL.
|
||||||
|
type DLL struct {
|
||||||
|
Name string
|
||||||
|
Handle Handle
|
||||||
|
}
|
||||||
|
|
||||||
|
// LoadDLL loads DLL file into memory.
|
||||||
|
//
|
||||||
|
// Warning: using LoadDLL without an absolute path name is subject to
|
||||||
|
// DLL preloading attacks. To safely load a system DLL, use LazyDLL
|
||||||
|
// with System set to true, or use LoadLibraryEx directly.
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
//go:uintptrescapes
|
||||||
|
|
||||||
|
// 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 windows.Errno.
|
||||||
|
func (p *Proc) Call(a ...uintptr) (r1, r2 uintptr, lastErr error) {
|
||||||
|
switch len(a) {
|
||||||
|
case 0:
|
||||||
|
return syscall.Syscall(p.Addr(), uintptr(len(a)), 0, 0, 0)
|
||||||
|
case 1:
|
||||||
|
return syscall.Syscall(p.Addr(), uintptr(len(a)), a[0], 0, 0)
|
||||||
|
case 2:
|
||||||
|
return syscall.Syscall(p.Addr(), uintptr(len(a)), a[0], a[1], 0)
|
||||||
|
case 3:
|
||||||
|
return syscall.Syscall(p.Addr(), uintptr(len(a)), a[0], a[1], a[2])
|
||||||
|
case 4:
|
||||||
|
return syscall.Syscall6(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], 0, 0)
|
||||||
|
case 5:
|
||||||
|
return syscall.Syscall6(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], 0)
|
||||||
|
case 6:
|
||||||
|
return syscall.Syscall6(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5])
|
||||||
|
case 7:
|
||||||
|
return syscall.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 syscall.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 syscall.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 syscall.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 syscall.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 syscall.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 syscall.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 syscall.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 syscall.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 {
|
||||||
|
Name string
|
||||||
|
|
||||||
|
// System determines whether the DLL must be loaded from the
|
||||||
|
// Windows System directory, bypassing the normal DLL search
|
||||||
|
// path.
|
||||||
|
System bool
|
||||||
|
|
||||||
|
mu sync.Mutex
|
||||||
|
dll *DLL // non nil once DLL is loaded
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
d.mu.Lock()
|
||||||
|
defer d.mu.Unlock()
|
||||||
|
if d.dll != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// kernel32.dll is special, since it's where LoadLibraryEx comes from.
|
||||||
|
// The kernel already special-cases its name, so it's always
|
||||||
|
// loaded from system32.
|
||||||
|
var dll *DLL
|
||||||
|
var err error
|
||||||
|
if d.Name == "kernel32.dll" {
|
||||||
|
dll, err = LoadDLL(d.Name)
|
||||||
|
} else {
|
||||||
|
dll, err = loadLibraryEx(d.Name, d.System)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewLazySystemDLL is like NewLazyDLL, but will only
|
||||||
|
// search Windows System directory for the DLL if name is
|
||||||
|
// a base name (like "advapi32.dll").
|
||||||
|
func NewLazySystemDLL(name string) *LazyDLL {
|
||||||
|
return &LazyDLL{Name: name, System: true}
|
||||||
|
}
|
||||||
|
|
||||||
|
// A LazyProc implements access to a procedure inside a LazyDLL.
|
||||||
|
// It delays the lookup until the Addr method is called.
|
||||||
|
type LazyProc struct {
|
||||||
|
Name string
|
||||||
|
|
||||||
|
mu sync.Mutex
|
||||||
|
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()
|
||||||
|
}
|
||||||
|
|
||||||
|
//go:uintptrescapes
|
||||||
|
|
||||||
|
// 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 windows.Errno.
|
||||||
|
func (p *LazyProc) Call(a ...uintptr) (r1, r2 uintptr, lastErr error) {
|
||||||
|
p.mustFind()
|
||||||
|
return p.proc.Call(a...)
|
||||||
|
}
|
||||||
|
|
||||||
|
var canDoSearchSystem32Once struct {
|
||||||
|
sync.Once
|
||||||
|
v bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func initCanDoSearchSystem32() {
|
||||||
|
// https://msdn.microsoft.com/en-us/library/ms684179(v=vs.85).aspx says:
|
||||||
|
// "Windows 7, Windows Server 2008 R2, Windows Vista, and Windows
|
||||||
|
// Server 2008: The LOAD_LIBRARY_SEARCH_* flags are available on
|
||||||
|
// systems that have KB2533623 installed. To determine whether the
|
||||||
|
// flags are available, use GetProcAddress to get the address of the
|
||||||
|
// AddDllDirectory, RemoveDllDirectory, or SetDefaultDllDirectories
|
||||||
|
// function. If GetProcAddress succeeds, the LOAD_LIBRARY_SEARCH_*
|
||||||
|
// flags can be used with LoadLibraryEx."
|
||||||
|
canDoSearchSystem32Once.v = (modkernel32.NewProc("AddDllDirectory").Find() == nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func canDoSearchSystem32() bool {
|
||||||
|
canDoSearchSystem32Once.Do(initCanDoSearchSystem32)
|
||||||
|
return canDoSearchSystem32Once.v
|
||||||
|
}
|
||||||
|
|
||||||
|
func isBaseName(name string) bool {
|
||||||
|
for _, c := range name {
|
||||||
|
if c == ':' || c == '/' || c == '\\' {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// loadLibraryEx wraps the Windows LoadLibraryEx function.
|
||||||
|
//
|
||||||
|
// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms684179(v=vs.85).aspx
|
||||||
|
//
|
||||||
|
// If name is not an absolute path, LoadLibraryEx searches for the DLL
|
||||||
|
// in a variety of automatic locations unless constrained by flags.
|
||||||
|
// See: https://msdn.microsoft.com/en-us/library/ff919712%28VS.85%29.aspx
|
||||||
|
func loadLibraryEx(name string, system bool) (*DLL, error) {
|
||||||
|
loadDLL := name
|
||||||
|
var flags uintptr
|
||||||
|
if system {
|
||||||
|
if canDoSearchSystem32() {
|
||||||
|
const LOAD_LIBRARY_SEARCH_SYSTEM32 = 0x00000800
|
||||||
|
flags = LOAD_LIBRARY_SEARCH_SYSTEM32
|
||||||
|
} else if isBaseName(name) {
|
||||||
|
// WindowsXP or unpatched Windows machine
|
||||||
|
// trying to load "foo.dll" out of the system
|
||||||
|
// folder, but LoadLibraryEx doesn't support
|
||||||
|
// that yet on their system, so emulate it.
|
||||||
|
windir, _ := Getenv("WINDIR") // old var; apparently works on XP
|
||||||
|
if windir == "" {
|
||||||
|
return nil, errString("%WINDIR% not defined")
|
||||||
|
}
|
||||||
|
loadDLL = windir + "\\System32\\" + name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
h, err := LoadLibraryEx(loadDLL, 0, flags)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &DLL{Name: name, Handle: h}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type errString string
|
||||||
|
|
||||||
|
func (s errString) Error() string { return string(s) }
|
|
@ -0,0 +1,15 @@
|
||||||
|
// Copyright 2014 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 windows
|
||||||
|
// +build go1.4
|
||||||
|
|
||||||
|
package windows
|
||||||
|
|
||||||
|
import "syscall"
|
||||||
|
|
||||||
|
func Unsetenv(key string) error {
|
||||||
|
// This was added in Go 1.4.
|
||||||
|
return syscall.Unsetenv(key)
|
||||||
|
}
|
|
@ -0,0 +1,25 @@
|
||||||
|
// 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 windows
|
||||||
|
|
||||||
|
import "syscall"
|
||||||
|
|
||||||
|
func Getenv(key string) (value string, found bool) {
|
||||||
|
return syscall.Getenv(key)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Setenv(key, value string) error {
|
||||||
|
return syscall.Setenv(key, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Clearenv() {
|
||||||
|
syscall.Clearenv()
|
||||||
|
}
|
||||||
|
|
||||||
|
func Environ() []string {
|
||||||
|
return syscall.Environ()
|
||||||
|
}
|
|
@ -0,0 +1,20 @@
|
||||||
|
// 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 windows
|
||||||
|
|
||||||
|
package windows
|
||||||
|
|
||||||
|
const (
|
||||||
|
EVENTLOG_SUCCESS = 0
|
||||||
|
EVENTLOG_ERROR_TYPE = 1
|
||||||
|
EVENTLOG_WARNING_TYPE = 2
|
||||||
|
EVENTLOG_INFORMATION_TYPE = 4
|
||||||
|
EVENTLOG_AUDIT_SUCCESS = 8
|
||||||
|
EVENTLOG_AUDIT_FAILURE = 16
|
||||||
|
)
|
||||||
|
|
||||||
|
//sys RegisterEventSource(uncServerName *uint16, sourceName *uint16) (handle Handle, err error) [failretval==0] = advapi32.RegisterEventSourceW
|
||||||
|
//sys DeregisterEventSource(handle Handle) (err error) = advapi32.DeregisterEventSource
|
||||||
|
//sys ReportEvent(log Handle, etype uint16, category uint16, eventId uint32, usrSId uintptr, numStrings uint16, dataSize uint32, strings **uint16, rawData *byte) (err error) = advapi32.ReportEventW
|
|
@ -0,0 +1,97 @@
|
||||||
|
// 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 windows
|
||||||
|
|
||||||
|
// 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])
|
||||||
|
}
|
||||||
|
|
||||||
|
func CloseOnExec(fd Handle) {
|
||||||
|
SetHandleInformation(Handle(fd), HANDLE_FLAG_INHERIT, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
// FullPath retrieves the full path of the specified file.
|
||||||
|
func FullPath(name string) (path string, err error) {
|
||||||
|
p, err := UTF16PtrFromString(name)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
n := uint32(100)
|
||||||
|
for {
|
||||||
|
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 UTF16ToString(buf[:n]), nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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.
|
||||||
|
|
||||||
|
package windows
|
||||||
|
|
||||||
|
//go:generate go run $GOROOT/src/syscall/mksyscall_windows.go -output zsyscall_windows.go eventlog.go service.go syscall_windows.go security_windows.go
|
|
@ -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 windows,race
|
||||||
|
|
||||||
|
package windows
|
||||||
|
|
||||||
|
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 windows,!race
|
||||||
|
|
||||||
|
package windows
|
||||||
|
|
||||||
|
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,200 @@
|
||||||
|
// Copyright 2015 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 windows
|
||||||
|
|
||||||
|
// Package registry provides access to the Windows registry.
|
||||||
|
//
|
||||||
|
// Here is a simple example, opening a registry key and reading a string value from it.
|
||||||
|
//
|
||||||
|
// k, err := registry.OpenKey(registry.LOCAL_MACHINE, `SOFTWARE\Microsoft\Windows NT\CurrentVersion`, registry.QUERY_VALUE)
|
||||||
|
// if err != nil {
|
||||||
|
// log.Fatal(err)
|
||||||
|
// }
|
||||||
|
// defer k.Close()
|
||||||
|
//
|
||||||
|
// s, _, err := k.GetStringValue("SystemRoot")
|
||||||
|
// if err != nil {
|
||||||
|
// log.Fatal(err)
|
||||||
|
// }
|
||||||
|
// fmt.Printf("Windows system root is %q\n", s)
|
||||||
|
//
|
||||||
|
package registry
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io"
|
||||||
|
"syscall"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// Registry key security and access rights.
|
||||||
|
// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms724878.aspx
|
||||||
|
// for details.
|
||||||
|
ALL_ACCESS = 0xf003f
|
||||||
|
CREATE_LINK = 0x00020
|
||||||
|
CREATE_SUB_KEY = 0x00004
|
||||||
|
ENUMERATE_SUB_KEYS = 0x00008
|
||||||
|
EXECUTE = 0x20019
|
||||||
|
NOTIFY = 0x00010
|
||||||
|
QUERY_VALUE = 0x00001
|
||||||
|
READ = 0x20019
|
||||||
|
SET_VALUE = 0x00002
|
||||||
|
WOW64_32KEY = 0x00200
|
||||||
|
WOW64_64KEY = 0x00100
|
||||||
|
WRITE = 0x20006
|
||||||
|
)
|
||||||
|
|
||||||
|
// Key is a handle to an open Windows registry key.
|
||||||
|
// Keys can be obtained by calling OpenKey; there are
|
||||||
|
// also some predefined root keys such as CURRENT_USER.
|
||||||
|
// Keys can be used directly in the Windows API.
|
||||||
|
type Key syscall.Handle
|
||||||
|
|
||||||
|
const (
|
||||||
|
// Windows defines some predefined root keys that are always open.
|
||||||
|
// An application can use these keys as entry points to the registry.
|
||||||
|
// Normally these keys are used in OpenKey to open new keys,
|
||||||
|
// but they can also be used anywhere a Key is required.
|
||||||
|
CLASSES_ROOT = Key(syscall.HKEY_CLASSES_ROOT)
|
||||||
|
CURRENT_USER = Key(syscall.HKEY_CURRENT_USER)
|
||||||
|
LOCAL_MACHINE = Key(syscall.HKEY_LOCAL_MACHINE)
|
||||||
|
USERS = Key(syscall.HKEY_USERS)
|
||||||
|
CURRENT_CONFIG = Key(syscall.HKEY_CURRENT_CONFIG)
|
||||||
|
PERFORMANCE_DATA = Key(syscall.HKEY_PERFORMANCE_DATA)
|
||||||
|
)
|
||||||
|
|
||||||
|
// Close closes open key k.
|
||||||
|
func (k Key) Close() error {
|
||||||
|
return syscall.RegCloseKey(syscall.Handle(k))
|
||||||
|
}
|
||||||
|
|
||||||
|
// OpenKey opens a new key with path name relative to key k.
|
||||||
|
// It accepts any open key, including CURRENT_USER and others,
|
||||||
|
// and returns the new key and an error.
|
||||||
|
// The access parameter specifies desired access rights to the
|
||||||
|
// key to be opened.
|
||||||
|
func OpenKey(k Key, path string, access uint32) (Key, error) {
|
||||||
|
p, err := syscall.UTF16PtrFromString(path)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
var subkey syscall.Handle
|
||||||
|
err = syscall.RegOpenKeyEx(syscall.Handle(k), p, 0, access, &subkey)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
return Key(subkey), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// OpenRemoteKey opens a predefined registry key on another
|
||||||
|
// computer pcname. The key to be opened is specified by k, but
|
||||||
|
// can only be one of LOCAL_MACHINE, PERFORMANCE_DATA or USERS.
|
||||||
|
// If pcname is "", OpenRemoteKey returns local computer key.
|
||||||
|
func OpenRemoteKey(pcname string, k Key) (Key, error) {
|
||||||
|
var err error
|
||||||
|
var p *uint16
|
||||||
|
if pcname != "" {
|
||||||
|
p, err = syscall.UTF16PtrFromString(`\\` + pcname)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var remoteKey syscall.Handle
|
||||||
|
err = regConnectRegistry(p, syscall.Handle(k), &remoteKey)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
return Key(remoteKey), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReadSubKeyNames returns the names of subkeys of key k.
|
||||||
|
// The parameter n controls the number of returned names,
|
||||||
|
// analogous to the way os.File.Readdirnames works.
|
||||||
|
func (k Key) ReadSubKeyNames(n int) ([]string, error) {
|
||||||
|
ki, err := k.Stat()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
names := make([]string, 0, ki.SubKeyCount)
|
||||||
|
buf := make([]uint16, ki.MaxSubKeyLen+1) // extra room for terminating zero byte
|
||||||
|
loopItems:
|
||||||
|
for i := uint32(0); ; i++ {
|
||||||
|
if n > 0 {
|
||||||
|
if len(names) == n {
|
||||||
|
return names, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
l := uint32(len(buf))
|
||||||
|
for {
|
||||||
|
err := syscall.RegEnumKeyEx(syscall.Handle(k), i, &buf[0], &l, nil, nil, nil, nil)
|
||||||
|
if err == nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if err == syscall.ERROR_MORE_DATA {
|
||||||
|
// Double buffer size and try again.
|
||||||
|
l = uint32(2 * len(buf))
|
||||||
|
buf = make([]uint16, l)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if err == _ERROR_NO_MORE_ITEMS {
|
||||||
|
break loopItems
|
||||||
|
}
|
||||||
|
return names, err
|
||||||
|
}
|
||||||
|
names = append(names, syscall.UTF16ToString(buf[:l]))
|
||||||
|
}
|
||||||
|
if n > len(names) {
|
||||||
|
return names, io.EOF
|
||||||
|
}
|
||||||
|
return names, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateKey creates a key named path under open key k.
|
||||||
|
// CreateKey returns the new key and a boolean flag that reports
|
||||||
|
// whether the key already existed.
|
||||||
|
// The access parameter specifies the access rights for the key
|
||||||
|
// to be created.
|
||||||
|
func CreateKey(k Key, path string, access uint32) (newk Key, openedExisting bool, err error) {
|
||||||
|
var h syscall.Handle
|
||||||
|
var d uint32
|
||||||
|
err = regCreateKeyEx(syscall.Handle(k), syscall.StringToUTF16Ptr(path),
|
||||||
|
0, nil, _REG_OPTION_NON_VOLATILE, access, nil, &h, &d)
|
||||||
|
if err != nil {
|
||||||
|
return 0, false, err
|
||||||
|
}
|
||||||
|
return Key(h), d == _REG_OPENED_EXISTING_KEY, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteKey deletes the subkey path of key k and its values.
|
||||||
|
func DeleteKey(k Key, path string) error {
|
||||||
|
return regDeleteKey(syscall.Handle(k), syscall.StringToUTF16Ptr(path))
|
||||||
|
}
|
||||||
|
|
||||||
|
// A KeyInfo describes the statistics of a key. It is returned by Stat.
|
||||||
|
type KeyInfo struct {
|
||||||
|
SubKeyCount uint32
|
||||||
|
MaxSubKeyLen uint32 // size of the key's subkey with the longest name, in Unicode characters, not including the terminating zero byte
|
||||||
|
ValueCount uint32
|
||||||
|
MaxValueNameLen uint32 // size of the key's longest value name, in Unicode characters, not including the terminating zero byte
|
||||||
|
MaxValueLen uint32 // longest data component among the key's values, in bytes
|
||||||
|
lastWriteTime syscall.Filetime
|
||||||
|
}
|
||||||
|
|
||||||
|
// ModTime returns the key's last write time.
|
||||||
|
func (ki *KeyInfo) ModTime() time.Time {
|
||||||
|
return time.Unix(0, ki.lastWriteTime.Nanoseconds())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stat retrieves information about the open key k.
|
||||||
|
func (k Key) Stat() (*KeyInfo, error) {
|
||||||
|
var ki KeyInfo
|
||||||
|
err := syscall.RegQueryInfoKey(syscall.Handle(k), nil, nil, nil,
|
||||||
|
&ki.SubKeyCount, &ki.MaxSubKeyLen, nil, &ki.ValueCount,
|
||||||
|
&ki.MaxValueNameLen, &ki.MaxValueLen, nil, &ki.lastWriteTime)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &ki, nil
|
||||||
|
}
|
|
@ -0,0 +1,7 @@
|
||||||
|
// Copyright 2015 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 registry
|
||||||
|
|
||||||
|
//go:generate go run $GOROOT/src/syscall/mksyscall_windows.go -output zsyscall_windows.go syscall.go
|
|
@ -0,0 +1,32 @@
|
||||||
|
// Copyright 2015 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 windows
|
||||||
|
|
||||||
|
package registry
|
||||||
|
|
||||||
|
import "syscall"
|
||||||
|
|
||||||
|
const (
|
||||||
|
_REG_OPTION_NON_VOLATILE = 0
|
||||||
|
|
||||||
|
_REG_CREATED_NEW_KEY = 1
|
||||||
|
_REG_OPENED_EXISTING_KEY = 2
|
||||||
|
|
||||||
|
_ERROR_NO_MORE_ITEMS syscall.Errno = 259
|
||||||
|
)
|
||||||
|
|
||||||
|
func LoadRegLoadMUIString() error {
|
||||||
|
return procRegLoadMUIStringW.Find()
|
||||||
|
}
|
||||||
|
|
||||||
|
//sys regCreateKeyEx(key syscall.Handle, subkey *uint16, reserved uint32, class *uint16, options uint32, desired uint32, sa *syscall.SecurityAttributes, result *syscall.Handle, disposition *uint32) (regerrno error) = advapi32.RegCreateKeyExW
|
||||||
|
//sys regDeleteKey(key syscall.Handle, subkey *uint16) (regerrno error) = advapi32.RegDeleteKeyW
|
||||||
|
//sys regSetValueEx(key syscall.Handle, valueName *uint16, reserved uint32, vtype uint32, buf *byte, bufsize uint32) (regerrno error) = advapi32.RegSetValueExW
|
||||||
|
//sys regEnumValue(key syscall.Handle, index uint32, name *uint16, nameLen *uint32, reserved *uint32, valtype *uint32, buf *byte, buflen *uint32) (regerrno error) = advapi32.RegEnumValueW
|
||||||
|
//sys regDeleteValue(key syscall.Handle, name *uint16) (regerrno error) = advapi32.RegDeleteValueW
|
||||||
|
//sys regLoadMUIString(key syscall.Handle, name *uint16, buf *uint16, buflen uint32, buflenCopied *uint32, flags uint32, dir *uint16) (regerrno error) = advapi32.RegLoadMUIStringW
|
||||||
|
//sys regConnectRegistry(machinename *uint16, key syscall.Handle, result *syscall.Handle) (regerrno error) = advapi32.RegConnectRegistryW
|
||||||
|
|
||||||
|
//sys expandEnvironmentStrings(src *uint16, dst *uint16, size uint32) (n uint32, err error) = kernel32.ExpandEnvironmentStringsW
|
|
@ -0,0 +1,384 @@
|
||||||
|
// Copyright 2015 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 windows
|
||||||
|
|
||||||
|
package registry
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"io"
|
||||||
|
"syscall"
|
||||||
|
"unicode/utf16"
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// Registry value types.
|
||||||
|
NONE = 0
|
||||||
|
SZ = 1
|
||||||
|
EXPAND_SZ = 2
|
||||||
|
BINARY = 3
|
||||||
|
DWORD = 4
|
||||||
|
DWORD_BIG_ENDIAN = 5
|
||||||
|
LINK = 6
|
||||||
|
MULTI_SZ = 7
|
||||||
|
RESOURCE_LIST = 8
|
||||||
|
FULL_RESOURCE_DESCRIPTOR = 9
|
||||||
|
RESOURCE_REQUIREMENTS_LIST = 10
|
||||||
|
QWORD = 11
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
// ErrShortBuffer is returned when the buffer was too short for the operation.
|
||||||
|
ErrShortBuffer = syscall.ERROR_MORE_DATA
|
||||||
|
|
||||||
|
// ErrNotExist is returned when a registry key or value does not exist.
|
||||||
|
ErrNotExist = syscall.ERROR_FILE_NOT_FOUND
|
||||||
|
|
||||||
|
// ErrUnexpectedType is returned by Get*Value when the value's type was unexpected.
|
||||||
|
ErrUnexpectedType = errors.New("unexpected key value type")
|
||||||
|
)
|
||||||
|
|
||||||
|
// GetValue retrieves the type and data for the specified value associated
|
||||||
|
// with an open key k. It fills up buffer buf and returns the retrieved
|
||||||
|
// byte count n. If buf is too small to fit the stored value it returns
|
||||||
|
// ErrShortBuffer error along with the required buffer size n.
|
||||||
|
// If no buffer is provided, it returns true and actual buffer size n.
|
||||||
|
// If no buffer is provided, GetValue returns the value's type only.
|
||||||
|
// If the value does not exist, the error returned is ErrNotExist.
|
||||||
|
//
|
||||||
|
// GetValue is a low level function. If value's type is known, use the appropriate
|
||||||
|
// Get*Value function instead.
|
||||||
|
func (k Key) GetValue(name string, buf []byte) (n int, valtype uint32, err error) {
|
||||||
|
pname, err := syscall.UTF16PtrFromString(name)
|
||||||
|
if err != nil {
|
||||||
|
return 0, 0, err
|
||||||
|
}
|
||||||
|
var pbuf *byte
|
||||||
|
if len(buf) > 0 {
|
||||||
|
pbuf = (*byte)(unsafe.Pointer(&buf[0]))
|
||||||
|
}
|
||||||
|
l := uint32(len(buf))
|
||||||
|
err = syscall.RegQueryValueEx(syscall.Handle(k), pname, nil, &valtype, pbuf, &l)
|
||||||
|
if err != nil {
|
||||||
|
return int(l), valtype, err
|
||||||
|
}
|
||||||
|
return int(l), valtype, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (k Key) getValue(name string, buf []byte) (date []byte, valtype uint32, err error) {
|
||||||
|
p, err := syscall.UTF16PtrFromString(name)
|
||||||
|
if err != nil {
|
||||||
|
return nil, 0, err
|
||||||
|
}
|
||||||
|
var t uint32
|
||||||
|
n := uint32(len(buf))
|
||||||
|
for {
|
||||||
|
err = syscall.RegQueryValueEx(syscall.Handle(k), p, nil, &t, (*byte)(unsafe.Pointer(&buf[0])), &n)
|
||||||
|
if err == nil {
|
||||||
|
return buf[:n], t, nil
|
||||||
|
}
|
||||||
|
if err != syscall.ERROR_MORE_DATA {
|
||||||
|
return nil, 0, err
|
||||||
|
}
|
||||||
|
if n <= uint32(len(buf)) {
|
||||||
|
return nil, 0, err
|
||||||
|
}
|
||||||
|
buf = make([]byte, n)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetStringValue retrieves the string value for the specified
|
||||||
|
// value name associated with an open key k. It also returns the value's type.
|
||||||
|
// If value does not exist, GetStringValue returns ErrNotExist.
|
||||||
|
// If value is not SZ or EXPAND_SZ, it will return the correct value
|
||||||
|
// type and ErrUnexpectedType.
|
||||||
|
func (k Key) GetStringValue(name string) (val string, valtype uint32, err error) {
|
||||||
|
data, typ, err2 := k.getValue(name, make([]byte, 64))
|
||||||
|
if err2 != nil {
|
||||||
|
return "", typ, err2
|
||||||
|
}
|
||||||
|
switch typ {
|
||||||
|
case SZ, EXPAND_SZ:
|
||||||
|
default:
|
||||||
|
return "", typ, ErrUnexpectedType
|
||||||
|
}
|
||||||
|
if len(data) == 0 {
|
||||||
|
return "", typ, nil
|
||||||
|
}
|
||||||
|
u := (*[1 << 29]uint16)(unsafe.Pointer(&data[0]))[:]
|
||||||
|
return syscall.UTF16ToString(u), typ, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetMUIStringValue retrieves the localized string value for
|
||||||
|
// the specified value name associated with an open key k.
|
||||||
|
// If the value name doesn't exist or the localized string value
|
||||||
|
// can't be resolved, GetMUIStringValue returns ErrNotExist.
|
||||||
|
// GetMUIStringValue panics if the system doesn't support
|
||||||
|
// regLoadMUIString; use LoadRegLoadMUIString to check if
|
||||||
|
// regLoadMUIString is supported before calling this function.
|
||||||
|
func (k Key) GetMUIStringValue(name string) (string, error) {
|
||||||
|
pname, err := syscall.UTF16PtrFromString(name)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
buf := make([]uint16, 1024)
|
||||||
|
var buflen uint32
|
||||||
|
var pdir *uint16
|
||||||
|
|
||||||
|
err = regLoadMUIString(syscall.Handle(k), pname, &buf[0], uint32(len(buf)), &buflen, 0, pdir)
|
||||||
|
if err == syscall.ERROR_FILE_NOT_FOUND { // Try fallback path
|
||||||
|
|
||||||
|
// Try to resolve the string value using the system directory as
|
||||||
|
// a DLL search path; this assumes the string value is of the form
|
||||||
|
// @[path]\dllname,-strID but with no path given, e.g. @tzres.dll,-320.
|
||||||
|
|
||||||
|
// This approach works with tzres.dll but may have to be revised
|
||||||
|
// in the future to allow callers to provide custom search paths.
|
||||||
|
|
||||||
|
var s string
|
||||||
|
s, err = ExpandString("%SystemRoot%\\system32\\")
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
pdir, err = syscall.UTF16PtrFromString(s)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = regLoadMUIString(syscall.Handle(k), pname, &buf[0], uint32(len(buf)), &buflen, 0, pdir)
|
||||||
|
}
|
||||||
|
|
||||||
|
for err == syscall.ERROR_MORE_DATA { // Grow buffer if needed
|
||||||
|
if buflen <= uint32(len(buf)) {
|
||||||
|
break // Buffer not growing, assume race; break
|
||||||
|
}
|
||||||
|
buf = make([]uint16, buflen)
|
||||||
|
err = regLoadMUIString(syscall.Handle(k), pname, &buf[0], uint32(len(buf)), &buflen, 0, pdir)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
return syscall.UTF16ToString(buf), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ExpandString expands environment-variable strings and replaces
|
||||||
|
// them with the values defined for the current user.
|
||||||
|
// Use ExpandString to expand EXPAND_SZ strings.
|
||||||
|
func ExpandString(value string) (string, error) {
|
||||||
|
if value == "" {
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
|
p, err := syscall.UTF16PtrFromString(value)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
r := make([]uint16, 100)
|
||||||
|
for {
|
||||||
|
n, err := expandEnvironmentStrings(p, &r[0], uint32(len(r)))
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
if n <= uint32(len(r)) {
|
||||||
|
u := (*[1 << 29]uint16)(unsafe.Pointer(&r[0]))[:]
|
||||||
|
return syscall.UTF16ToString(u), nil
|
||||||
|
}
|
||||||
|
r = make([]uint16, n)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetStringsValue retrieves the []string value for the specified
|
||||||
|
// value name associated with an open key k. It also returns the value's type.
|
||||||
|
// If value does not exist, GetStringsValue returns ErrNotExist.
|
||||||
|
// If value is not MULTI_SZ, it will return the correct value
|
||||||
|
// type and ErrUnexpectedType.
|
||||||
|
func (k Key) GetStringsValue(name string) (val []string, valtype uint32, err error) {
|
||||||
|
data, typ, err2 := k.getValue(name, make([]byte, 64))
|
||||||
|
if err2 != nil {
|
||||||
|
return nil, typ, err2
|
||||||
|
}
|
||||||
|
if typ != MULTI_SZ {
|
||||||
|
return nil, typ, ErrUnexpectedType
|
||||||
|
}
|
||||||
|
if len(data) == 0 {
|
||||||
|
return nil, typ, nil
|
||||||
|
}
|
||||||
|
p := (*[1 << 29]uint16)(unsafe.Pointer(&data[0]))[:len(data)/2]
|
||||||
|
if len(p) == 0 {
|
||||||
|
return nil, typ, nil
|
||||||
|
}
|
||||||
|
if p[len(p)-1] == 0 {
|
||||||
|
p = p[:len(p)-1] // remove terminating null
|
||||||
|
}
|
||||||
|
val = make([]string, 0, 5)
|
||||||
|
from := 0
|
||||||
|
for i, c := range p {
|
||||||
|
if c == 0 {
|
||||||
|
val = append(val, string(utf16.Decode(p[from:i])))
|
||||||
|
from = i + 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return val, typ, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetIntegerValue retrieves the integer value for the specified
|
||||||
|
// value name associated with an open key k. It also returns the value's type.
|
||||||
|
// If value does not exist, GetIntegerValue returns ErrNotExist.
|
||||||
|
// If value is not DWORD or QWORD, it will return the correct value
|
||||||
|
// type and ErrUnexpectedType.
|
||||||
|
func (k Key) GetIntegerValue(name string) (val uint64, valtype uint32, err error) {
|
||||||
|
data, typ, err2 := k.getValue(name, make([]byte, 8))
|
||||||
|
if err2 != nil {
|
||||||
|
return 0, typ, err2
|
||||||
|
}
|
||||||
|
switch typ {
|
||||||
|
case DWORD:
|
||||||
|
if len(data) != 4 {
|
||||||
|
return 0, typ, errors.New("DWORD value is not 4 bytes long")
|
||||||
|
}
|
||||||
|
return uint64(*(*uint32)(unsafe.Pointer(&data[0]))), DWORD, nil
|
||||||
|
case QWORD:
|
||||||
|
if len(data) != 8 {
|
||||||
|
return 0, typ, errors.New("QWORD value is not 8 bytes long")
|
||||||
|
}
|
||||||
|
return uint64(*(*uint64)(unsafe.Pointer(&data[0]))), QWORD, nil
|
||||||
|
default:
|
||||||
|
return 0, typ, ErrUnexpectedType
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetBinaryValue retrieves the binary value for the specified
|
||||||
|
// value name associated with an open key k. It also returns the value's type.
|
||||||
|
// If value does not exist, GetBinaryValue returns ErrNotExist.
|
||||||
|
// If value is not BINARY, it will return the correct value
|
||||||
|
// type and ErrUnexpectedType.
|
||||||
|
func (k Key) GetBinaryValue(name string) (val []byte, valtype uint32, err error) {
|
||||||
|
data, typ, err2 := k.getValue(name, make([]byte, 64))
|
||||||
|
if err2 != nil {
|
||||||
|
return nil, typ, err2
|
||||||
|
}
|
||||||
|
if typ != BINARY {
|
||||||
|
return nil, typ, ErrUnexpectedType
|
||||||
|
}
|
||||||
|
return data, typ, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (k Key) setValue(name string, valtype uint32, data []byte) error {
|
||||||
|
p, err := syscall.UTF16PtrFromString(name)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if len(data) == 0 {
|
||||||
|
return regSetValueEx(syscall.Handle(k), p, 0, valtype, nil, 0)
|
||||||
|
}
|
||||||
|
return regSetValueEx(syscall.Handle(k), p, 0, valtype, &data[0], uint32(len(data)))
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetDWordValue sets the data and type of a name value
|
||||||
|
// under key k to value and DWORD.
|
||||||
|
func (k Key) SetDWordValue(name string, value uint32) error {
|
||||||
|
return k.setValue(name, DWORD, (*[4]byte)(unsafe.Pointer(&value))[:])
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetQWordValue sets the data and type of a name value
|
||||||
|
// under key k to value and QWORD.
|
||||||
|
func (k Key) SetQWordValue(name string, value uint64) error {
|
||||||
|
return k.setValue(name, QWORD, (*[8]byte)(unsafe.Pointer(&value))[:])
|
||||||
|
}
|
||||||
|
|
||||||
|
func (k Key) setStringValue(name string, valtype uint32, value string) error {
|
||||||
|
v, err := syscall.UTF16FromString(value)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
buf := (*[1 << 29]byte)(unsafe.Pointer(&v[0]))[:len(v)*2]
|
||||||
|
return k.setValue(name, valtype, buf)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetStringValue sets the data and type of a name value
|
||||||
|
// under key k to value and SZ. The value must not contain a zero byte.
|
||||||
|
func (k Key) SetStringValue(name, value string) error {
|
||||||
|
return k.setStringValue(name, SZ, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetExpandStringValue sets the data and type of a name value
|
||||||
|
// under key k to value and EXPAND_SZ. The value must not contain a zero byte.
|
||||||
|
func (k Key) SetExpandStringValue(name, value string) error {
|
||||||
|
return k.setStringValue(name, EXPAND_SZ, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetStringsValue sets the data and type of a name value
|
||||||
|
// under key k to value and MULTI_SZ. The value strings
|
||||||
|
// must not contain a zero byte.
|
||||||
|
func (k Key) SetStringsValue(name string, value []string) error {
|
||||||
|
ss := ""
|
||||||
|
for _, s := range value {
|
||||||
|
for i := 0; i < len(s); i++ {
|
||||||
|
if s[i] == 0 {
|
||||||
|
return errors.New("string cannot have 0 inside")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ss += s + "\x00"
|
||||||
|
}
|
||||||
|
v := utf16.Encode([]rune(ss + "\x00"))
|
||||||
|
buf := (*[1 << 29]byte)(unsafe.Pointer(&v[0]))[:len(v)*2]
|
||||||
|
return k.setValue(name, MULTI_SZ, buf)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetBinaryValue sets the data and type of a name value
|
||||||
|
// under key k to value and BINARY.
|
||||||
|
func (k Key) SetBinaryValue(name string, value []byte) error {
|
||||||
|
return k.setValue(name, BINARY, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteValue removes a named value from the key k.
|
||||||
|
func (k Key) DeleteValue(name string) error {
|
||||||
|
return regDeleteValue(syscall.Handle(k), syscall.StringToUTF16Ptr(name))
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReadValueNames returns the value names of key k.
|
||||||
|
// The parameter n controls the number of returned names,
|
||||||
|
// analogous to the way os.File.Readdirnames works.
|
||||||
|
func (k Key) ReadValueNames(n int) ([]string, error) {
|
||||||
|
ki, err := k.Stat()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
names := make([]string, 0, ki.ValueCount)
|
||||||
|
buf := make([]uint16, ki.MaxValueNameLen+1) // extra room for terminating null character
|
||||||
|
loopItems:
|
||||||
|
for i := uint32(0); ; i++ {
|
||||||
|
if n > 0 {
|
||||||
|
if len(names) == n {
|
||||||
|
return names, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
l := uint32(len(buf))
|
||||||
|
for {
|
||||||
|
err := regEnumValue(syscall.Handle(k), i, &buf[0], &l, nil, nil, nil, nil)
|
||||||
|
if err == nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if err == syscall.ERROR_MORE_DATA {
|
||||||
|
// Double buffer size and try again.
|
||||||
|
l = uint32(2 * len(buf))
|
||||||
|
buf = make([]uint16, l)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if err == _ERROR_NO_MORE_ITEMS {
|
||||||
|
break loopItems
|
||||||
|
}
|
||||||
|
return names, err
|
||||||
|
}
|
||||||
|
names = append(names, syscall.UTF16ToString(buf[:l]))
|
||||||
|
}
|
||||||
|
if n > len(names) {
|
||||||
|
return names, io.EOF
|
||||||
|
}
|
||||||
|
return names, nil
|
||||||
|
}
|
|
@ -0,0 +1,120 @@
|
||||||
|
// MACHINE GENERATED BY 'go generate' COMMAND; DO NOT EDIT
|
||||||
|
|
||||||
|
package registry
|
||||||
|
|
||||||
|
import (
|
||||||
|
"syscall"
|
||||||
|
"unsafe"
|
||||||
|
|
||||||
|
"golang.org/x/sys/windows"
|
||||||
|
)
|
||||||
|
|
||||||
|
var _ unsafe.Pointer
|
||||||
|
|
||||||
|
// Do the interface allocations only once for common
|
||||||
|
// Errno values.
|
||||||
|
const (
|
||||||
|
errnoERROR_IO_PENDING = 997
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
errERROR_IO_PENDING error = syscall.Errno(errnoERROR_IO_PENDING)
|
||||||
|
)
|
||||||
|
|
||||||
|
// errnoErr returns common boxed Errno values, to prevent
|
||||||
|
// allocations at runtime.
|
||||||
|
func errnoErr(e syscall.Errno) error {
|
||||||
|
switch e {
|
||||||
|
case 0:
|
||||||
|
return nil
|
||||||
|
case errnoERROR_IO_PENDING:
|
||||||
|
return errERROR_IO_PENDING
|
||||||
|
}
|
||||||
|
// TODO: add more here, after collecting data on the common
|
||||||
|
// error values see on Windows. (perhaps when running
|
||||||
|
// all.bat?)
|
||||||
|
return e
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
modadvapi32 = windows.NewLazySystemDLL("advapi32.dll")
|
||||||
|
modkernel32 = windows.NewLazySystemDLL("kernel32.dll")
|
||||||
|
|
||||||
|
procRegCreateKeyExW = modadvapi32.NewProc("RegCreateKeyExW")
|
||||||
|
procRegDeleteKeyW = modadvapi32.NewProc("RegDeleteKeyW")
|
||||||
|
procRegSetValueExW = modadvapi32.NewProc("RegSetValueExW")
|
||||||
|
procRegEnumValueW = modadvapi32.NewProc("RegEnumValueW")
|
||||||
|
procRegDeleteValueW = modadvapi32.NewProc("RegDeleteValueW")
|
||||||
|
procRegLoadMUIStringW = modadvapi32.NewProc("RegLoadMUIStringW")
|
||||||
|
procRegConnectRegistryW = modadvapi32.NewProc("RegConnectRegistryW")
|
||||||
|
procExpandEnvironmentStringsW = modkernel32.NewProc("ExpandEnvironmentStringsW")
|
||||||
|
)
|
||||||
|
|
||||||
|
func regCreateKeyEx(key syscall.Handle, subkey *uint16, reserved uint32, class *uint16, options uint32, desired uint32, sa *syscall.SecurityAttributes, result *syscall.Handle, disposition *uint32) (regerrno error) {
|
||||||
|
r0, _, _ := syscall.Syscall9(procRegCreateKeyExW.Addr(), 9, uintptr(key), uintptr(unsafe.Pointer(subkey)), uintptr(reserved), uintptr(unsafe.Pointer(class)), uintptr(options), uintptr(desired), uintptr(unsafe.Pointer(sa)), uintptr(unsafe.Pointer(result)), uintptr(unsafe.Pointer(disposition)))
|
||||||
|
if r0 != 0 {
|
||||||
|
regerrno = syscall.Errno(r0)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func regDeleteKey(key syscall.Handle, subkey *uint16) (regerrno error) {
|
||||||
|
r0, _, _ := syscall.Syscall(procRegDeleteKeyW.Addr(), 2, uintptr(key), uintptr(unsafe.Pointer(subkey)), 0)
|
||||||
|
if r0 != 0 {
|
||||||
|
regerrno = syscall.Errno(r0)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func regSetValueEx(key syscall.Handle, valueName *uint16, reserved uint32, vtype uint32, buf *byte, bufsize uint32) (regerrno error) {
|
||||||
|
r0, _, _ := syscall.Syscall6(procRegSetValueExW.Addr(), 6, uintptr(key), uintptr(unsafe.Pointer(valueName)), uintptr(reserved), uintptr(vtype), uintptr(unsafe.Pointer(buf)), uintptr(bufsize))
|
||||||
|
if r0 != 0 {
|
||||||
|
regerrno = syscall.Errno(r0)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func regEnumValue(key syscall.Handle, index uint32, name *uint16, nameLen *uint32, reserved *uint32, valtype *uint32, buf *byte, buflen *uint32) (regerrno error) {
|
||||||
|
r0, _, _ := syscall.Syscall9(procRegEnumValueW.Addr(), 8, uintptr(key), uintptr(index), uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(nameLen)), uintptr(unsafe.Pointer(reserved)), uintptr(unsafe.Pointer(valtype)), uintptr(unsafe.Pointer(buf)), uintptr(unsafe.Pointer(buflen)), 0)
|
||||||
|
if r0 != 0 {
|
||||||
|
regerrno = syscall.Errno(r0)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func regDeleteValue(key syscall.Handle, name *uint16) (regerrno error) {
|
||||||
|
r0, _, _ := syscall.Syscall(procRegDeleteValueW.Addr(), 2, uintptr(key), uintptr(unsafe.Pointer(name)), 0)
|
||||||
|
if r0 != 0 {
|
||||||
|
regerrno = syscall.Errno(r0)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func regLoadMUIString(key syscall.Handle, name *uint16, buf *uint16, buflen uint32, buflenCopied *uint32, flags uint32, dir *uint16) (regerrno error) {
|
||||||
|
r0, _, _ := syscall.Syscall9(procRegLoadMUIStringW.Addr(), 7, uintptr(key), uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(buf)), uintptr(buflen), uintptr(unsafe.Pointer(buflenCopied)), uintptr(flags), uintptr(unsafe.Pointer(dir)), 0, 0)
|
||||||
|
if r0 != 0 {
|
||||||
|
regerrno = syscall.Errno(r0)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func regConnectRegistry(machinename *uint16, key syscall.Handle, result *syscall.Handle) (regerrno error) {
|
||||||
|
r0, _, _ := syscall.Syscall(procRegConnectRegistryW.Addr(), 3, uintptr(unsafe.Pointer(machinename)), uintptr(key), uintptr(unsafe.Pointer(result)))
|
||||||
|
if r0 != 0 {
|
||||||
|
regerrno = syscall.Errno(r0)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func expandEnvironmentStrings(src *uint16, dst *uint16, size uint32) (n uint32, err error) {
|
||||||
|
r0, _, e1 := syscall.Syscall(procExpandEnvironmentStringsW.Addr(), 3, uintptr(unsafe.Pointer(src)), uintptr(unsafe.Pointer(dst)), uintptr(size))
|
||||||
|
n = uint32(r0)
|
||||||
|
if n == 0 {
|
||||||
|
if e1 != 0 {
|
||||||
|
err = errnoErr(e1)
|
||||||
|
} else {
|
||||||
|
err = syscall.EINVAL
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
|
@ -0,0 +1,435 @@
|
||||||
|
// 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 windows
|
||||||
|
|
||||||
|
import (
|
||||||
|
"syscall"
|
||||||
|
"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
|
||||||
|
}
|
||||||
|
n := uint32(50)
|
||||||
|
for {
|
||||||
|
b := make([]uint16, n)
|
||||||
|
e = TranslateName(u, from, to, &b[0], &n)
|
||||||
|
if e == nil {
|
||||||
|
return UTF16ToString(b[:n]), nil
|
||||||
|
}
|
||||||
|
if e != ERROR_INSUFFICIENT_BUFFER {
|
||||||
|
return "", e
|
||||||
|
}
|
||||||
|
if n <= uint32(len(b)) {
|
||||||
|
return "", e
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
)
|
||||||
|
|
||||||
|
type SidIdentifierAuthority struct {
|
||||||
|
Value [6]byte
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
SECURITY_NULL_SID_AUTHORITY = SidIdentifierAuthority{[6]byte{0, 0, 0, 0, 0, 0}}
|
||||||
|
SECURITY_WORLD_SID_AUTHORITY = SidIdentifierAuthority{[6]byte{0, 0, 0, 0, 0, 1}}
|
||||||
|
SECURITY_LOCAL_SID_AUTHORITY = SidIdentifierAuthority{[6]byte{0, 0, 0, 0, 0, 2}}
|
||||||
|
SECURITY_CREATOR_SID_AUTHORITY = SidIdentifierAuthority{[6]byte{0, 0, 0, 0, 0, 3}}
|
||||||
|
SECURITY_NON_UNIQUE_AUTHORITY = SidIdentifierAuthority{[6]byte{0, 0, 0, 0, 0, 4}}
|
||||||
|
SECURITY_NT_AUTHORITY = SidIdentifierAuthority{[6]byte{0, 0, 0, 0, 0, 5}}
|
||||||
|
SECURITY_MANDATORY_LABEL_AUTHORITY = SidIdentifierAuthority{[6]byte{0, 0, 0, 0, 0, 16}}
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
SECURITY_NULL_RID = 0
|
||||||
|
SECURITY_WORLD_RID = 0
|
||||||
|
SECURITY_LOCAL_RID = 0
|
||||||
|
SECURITY_CREATOR_OWNER_RID = 0
|
||||||
|
SECURITY_CREATOR_GROUP_RID = 1
|
||||||
|
SECURITY_DIALUP_RID = 1
|
||||||
|
SECURITY_NETWORK_RID = 2
|
||||||
|
SECURITY_BATCH_RID = 3
|
||||||
|
SECURITY_INTERACTIVE_RID = 4
|
||||||
|
SECURITY_LOGON_IDS_RID = 5
|
||||||
|
SECURITY_SERVICE_RID = 6
|
||||||
|
SECURITY_LOCAL_SYSTEM_RID = 18
|
||||||
|
SECURITY_BUILTIN_DOMAIN_RID = 32
|
||||||
|
SECURITY_PRINCIPAL_SELF_RID = 10
|
||||||
|
SECURITY_CREATOR_OWNER_SERVER_RID = 0x2
|
||||||
|
SECURITY_CREATOR_GROUP_SERVER_RID = 0x3
|
||||||
|
SECURITY_LOGON_IDS_RID_COUNT = 0x3
|
||||||
|
SECURITY_ANONYMOUS_LOGON_RID = 0x7
|
||||||
|
SECURITY_PROXY_RID = 0x8
|
||||||
|
SECURITY_ENTERPRISE_CONTROLLERS_RID = 0x9
|
||||||
|
SECURITY_SERVER_LOGON_RID = SECURITY_ENTERPRISE_CONTROLLERS_RID
|
||||||
|
SECURITY_AUTHENTICATED_USER_RID = 0xb
|
||||||
|
SECURITY_RESTRICTED_CODE_RID = 0xc
|
||||||
|
SECURITY_NT_NON_UNIQUE_RID = 0x15
|
||||||
|
)
|
||||||
|
|
||||||
|
//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
|
||||||
|
//sys AllocateAndInitializeSid(identAuth *SidIdentifierAuthority, subAuth byte, subAuth0 uint32, subAuth1 uint32, subAuth2 uint32, subAuth3 uint32, subAuth4 uint32, subAuth5 uint32, subAuth6 uint32, subAuth7 uint32, sid **SID) (err error) = advapi32.AllocateAndInitializeSid
|
||||||
|
//sys FreeSid(sid *SID) (err error) [failretval!=0] = advapi32.FreeSid
|
||||||
|
//sys EqualSid(sid1 *SID, sid2 *SID) (isEqual bool) = advapi32.EqualSid
|
||||||
|
|
||||||
|
// 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, syscall.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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
n := uint32(50)
|
||||||
|
dn := uint32(50)
|
||||||
|
for {
|
||||||
|
b := make([]byte, n)
|
||||||
|
db := make([]uint16, dn)
|
||||||
|
sid = (*SID)(unsafe.Pointer(&b[0]))
|
||||||
|
e = LookupAccountName(sys, acc, sid, &n, &db[0], &dn, &accType)
|
||||||
|
if e == nil {
|
||||||
|
return sid, UTF16ToString(db), accType, nil
|
||||||
|
}
|
||||||
|
if e != ERROR_INSUFFICIENT_BUFFER {
|
||||||
|
return nil, "", 0, e
|
||||||
|
}
|
||||||
|
if n <= uint32(len(b)) {
|
||||||
|
return nil, "", 0, e
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
n := uint32(50)
|
||||||
|
dn := uint32(50)
|
||||||
|
for {
|
||||||
|
b := make([]uint16, n)
|
||||||
|
db := make([]uint16, dn)
|
||||||
|
e := LookupAccountSid(sys, sid, &b[0], &n, &db[0], &dn, &accType)
|
||||||
|
if e == nil {
|
||||||
|
return UTF16ToString(b), UTF16ToString(db), accType, nil
|
||||||
|
}
|
||||||
|
if e != ERROR_INSUFFICIENT_BUFFER {
|
||||||
|
return "", "", 0, e
|
||||||
|
}
|
||||||
|
if n <= uint32(len(b)) {
|
||||||
|
return "", "", 0, e
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
type Tokengroups struct {
|
||||||
|
GroupCount uint32
|
||||||
|
Groups [1]SIDAndAttributes
|
||||||
|
}
|
||||||
|
|
||||||
|
//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) {
|
||||||
|
n := uint32(initSize)
|
||||||
|
for {
|
||||||
|
b := make([]byte, n)
|
||||||
|
e := GetTokenInformation(t, class, &b[0], uint32(len(b)), &n)
|
||||||
|
if e == nil {
|
||||||
|
return unsafe.Pointer(&b[0]), nil
|
||||||
|
}
|
||||||
|
if e != ERROR_INSUFFICIENT_BUFFER {
|
||||||
|
return nil, e
|
||||||
|
}
|
||||||
|
if n <= uint32(len(b)) {
|
||||||
|
return nil, e
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetTokenGroups retrieves group accounts associated with access token t.
|
||||||
|
func (t Token) GetTokenGroups() (*Tokengroups, error) {
|
||||||
|
i, e := t.getInfo(TokenGroups, 50)
|
||||||
|
if e != nil {
|
||||||
|
return nil, e
|
||||||
|
}
|
||||||
|
return (*Tokengroups)(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) {
|
||||||
|
n := uint32(100)
|
||||||
|
for {
|
||||||
|
b := make([]uint16, n)
|
||||||
|
e := GetUserProfileDirectory(t, &b[0], &n)
|
||||||
|
if e == nil {
|
||||||
|
return UTF16ToString(b), nil
|
||||||
|
}
|
||||||
|
if e != ERROR_INSUFFICIENT_BUFFER {
|
||||||
|
return "", e
|
||||||
|
}
|
||||||
|
if n <= uint32(len(b)) {
|
||||||
|
return "", e
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,143 @@
|
||||||
|
// 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 windows
|
||||||
|
|
||||||
|
package windows
|
||||||
|
|
||||||
|
const (
|
||||||
|
SC_MANAGER_CONNECT = 1
|
||||||
|
SC_MANAGER_CREATE_SERVICE = 2
|
||||||
|
SC_MANAGER_ENUMERATE_SERVICE = 4
|
||||||
|
SC_MANAGER_LOCK = 8
|
||||||
|
SC_MANAGER_QUERY_LOCK_STATUS = 16
|
||||||
|
SC_MANAGER_MODIFY_BOOT_CONFIG = 32
|
||||||
|
SC_MANAGER_ALL_ACCESS = 0xf003f
|
||||||
|
)
|
||||||
|
|
||||||
|
//sys OpenSCManager(machineName *uint16, databaseName *uint16, access uint32) (handle Handle, err error) [failretval==0] = advapi32.OpenSCManagerW
|
||||||
|
|
||||||
|
const (
|
||||||
|
SERVICE_KERNEL_DRIVER = 1
|
||||||
|
SERVICE_FILE_SYSTEM_DRIVER = 2
|
||||||
|
SERVICE_ADAPTER = 4
|
||||||
|
SERVICE_RECOGNIZER_DRIVER = 8
|
||||||
|
SERVICE_WIN32_OWN_PROCESS = 16
|
||||||
|
SERVICE_WIN32_SHARE_PROCESS = 32
|
||||||
|
SERVICE_WIN32 = SERVICE_WIN32_OWN_PROCESS | SERVICE_WIN32_SHARE_PROCESS
|
||||||
|
SERVICE_INTERACTIVE_PROCESS = 256
|
||||||
|
SERVICE_DRIVER = SERVICE_KERNEL_DRIVER | SERVICE_FILE_SYSTEM_DRIVER | SERVICE_RECOGNIZER_DRIVER
|
||||||
|
SERVICE_TYPE_ALL = SERVICE_WIN32 | SERVICE_ADAPTER | SERVICE_DRIVER | SERVICE_INTERACTIVE_PROCESS
|
||||||
|
|
||||||
|
SERVICE_BOOT_START = 0
|
||||||
|
SERVICE_SYSTEM_START = 1
|
||||||
|
SERVICE_AUTO_START = 2
|
||||||
|
SERVICE_DEMAND_START = 3
|
||||||
|
SERVICE_DISABLED = 4
|
||||||
|
|
||||||
|
SERVICE_ERROR_IGNORE = 0
|
||||||
|
SERVICE_ERROR_NORMAL = 1
|
||||||
|
SERVICE_ERROR_SEVERE = 2
|
||||||
|
SERVICE_ERROR_CRITICAL = 3
|
||||||
|
|
||||||
|
SC_STATUS_PROCESS_INFO = 0
|
||||||
|
|
||||||
|
SERVICE_STOPPED = 1
|
||||||
|
SERVICE_START_PENDING = 2
|
||||||
|
SERVICE_STOP_PENDING = 3
|
||||||
|
SERVICE_RUNNING = 4
|
||||||
|
SERVICE_CONTINUE_PENDING = 5
|
||||||
|
SERVICE_PAUSE_PENDING = 6
|
||||||
|
SERVICE_PAUSED = 7
|
||||||
|
SERVICE_NO_CHANGE = 0xffffffff
|
||||||
|
|
||||||
|
SERVICE_ACCEPT_STOP = 1
|
||||||
|
SERVICE_ACCEPT_PAUSE_CONTINUE = 2
|
||||||
|
SERVICE_ACCEPT_SHUTDOWN = 4
|
||||||
|
SERVICE_ACCEPT_PARAMCHANGE = 8
|
||||||
|
SERVICE_ACCEPT_NETBINDCHANGE = 16
|
||||||
|
SERVICE_ACCEPT_HARDWAREPROFILECHANGE = 32
|
||||||
|
SERVICE_ACCEPT_POWEREVENT = 64
|
||||||
|
SERVICE_ACCEPT_SESSIONCHANGE = 128
|
||||||
|
|
||||||
|
SERVICE_CONTROL_STOP = 1
|
||||||
|
SERVICE_CONTROL_PAUSE = 2
|
||||||
|
SERVICE_CONTROL_CONTINUE = 3
|
||||||
|
SERVICE_CONTROL_INTERROGATE = 4
|
||||||
|
SERVICE_CONTROL_SHUTDOWN = 5
|
||||||
|
SERVICE_CONTROL_PARAMCHANGE = 6
|
||||||
|
SERVICE_CONTROL_NETBINDADD = 7
|
||||||
|
SERVICE_CONTROL_NETBINDREMOVE = 8
|
||||||
|
SERVICE_CONTROL_NETBINDENABLE = 9
|
||||||
|
SERVICE_CONTROL_NETBINDDISABLE = 10
|
||||||
|
SERVICE_CONTROL_DEVICEEVENT = 11
|
||||||
|
SERVICE_CONTROL_HARDWAREPROFILECHANGE = 12
|
||||||
|
SERVICE_CONTROL_POWEREVENT = 13
|
||||||
|
SERVICE_CONTROL_SESSIONCHANGE = 14
|
||||||
|
|
||||||
|
SERVICE_ACTIVE = 1
|
||||||
|
SERVICE_INACTIVE = 2
|
||||||
|
SERVICE_STATE_ALL = 3
|
||||||
|
|
||||||
|
SERVICE_QUERY_CONFIG = 1
|
||||||
|
SERVICE_CHANGE_CONFIG = 2
|
||||||
|
SERVICE_QUERY_STATUS = 4
|
||||||
|
SERVICE_ENUMERATE_DEPENDENTS = 8
|
||||||
|
SERVICE_START = 16
|
||||||
|
SERVICE_STOP = 32
|
||||||
|
SERVICE_PAUSE_CONTINUE = 64
|
||||||
|
SERVICE_INTERROGATE = 128
|
||||||
|
SERVICE_USER_DEFINED_CONTROL = 256
|
||||||
|
SERVICE_ALL_ACCESS = STANDARD_RIGHTS_REQUIRED | SERVICE_QUERY_CONFIG | SERVICE_CHANGE_CONFIG | SERVICE_QUERY_STATUS | SERVICE_ENUMERATE_DEPENDENTS | SERVICE_START | SERVICE_STOP | SERVICE_PAUSE_CONTINUE | SERVICE_INTERROGATE | SERVICE_USER_DEFINED_CONTROL
|
||||||
|
SERVICE_RUNS_IN_SYSTEM_PROCESS = 1
|
||||||
|
SERVICE_CONFIG_DESCRIPTION = 1
|
||||||
|
SERVICE_CONFIG_FAILURE_ACTIONS = 2
|
||||||
|
|
||||||
|
NO_ERROR = 0
|
||||||
|
)
|
||||||
|
|
||||||
|
type SERVICE_STATUS struct {
|
||||||
|
ServiceType uint32
|
||||||
|
CurrentState uint32
|
||||||
|
ControlsAccepted uint32
|
||||||
|
Win32ExitCode uint32
|
||||||
|
ServiceSpecificExitCode uint32
|
||||||
|
CheckPoint uint32
|
||||||
|
WaitHint uint32
|
||||||
|
}
|
||||||
|
|
||||||
|
type SERVICE_TABLE_ENTRY struct {
|
||||||
|
ServiceName *uint16
|
||||||
|
ServiceProc uintptr
|
||||||
|
}
|
||||||
|
|
||||||
|
type QUERY_SERVICE_CONFIG struct {
|
||||||
|
ServiceType uint32
|
||||||
|
StartType uint32
|
||||||
|
ErrorControl uint32
|
||||||
|
BinaryPathName *uint16
|
||||||
|
LoadOrderGroup *uint16
|
||||||
|
TagId uint32
|
||||||
|
Dependencies *uint16
|
||||||
|
ServiceStartName *uint16
|
||||||
|
DisplayName *uint16
|
||||||
|
}
|
||||||
|
|
||||||
|
type SERVICE_DESCRIPTION struct {
|
||||||
|
Description *uint16
|
||||||
|
}
|
||||||
|
|
||||||
|
//sys CloseServiceHandle(handle Handle) (err error) = advapi32.CloseServiceHandle
|
||||||
|
//sys CreateService(mgr Handle, serviceName *uint16, displayName *uint16, access uint32, srvType uint32, startType uint32, errCtl uint32, pathName *uint16, loadOrderGroup *uint16, tagId *uint32, dependencies *uint16, serviceStartName *uint16, password *uint16) (handle Handle, err error) [failretval==0] = advapi32.CreateServiceW
|
||||||
|
//sys OpenService(mgr Handle, serviceName *uint16, access uint32) (handle Handle, err error) [failretval==0] = advapi32.OpenServiceW
|
||||||
|
//sys DeleteService(service Handle) (err error) = advapi32.DeleteService
|
||||||
|
//sys StartService(service Handle, numArgs uint32, argVectors **uint16) (err error) = advapi32.StartServiceW
|
||||||
|
//sys QueryServiceStatus(service Handle, status *SERVICE_STATUS) (err error) = advapi32.QueryServiceStatus
|
||||||
|
//sys ControlService(service Handle, control uint32, status *SERVICE_STATUS) (err error) = advapi32.ControlService
|
||||||
|
//sys StartServiceCtrlDispatcher(serviceTable *SERVICE_TABLE_ENTRY) (err error) = advapi32.StartServiceCtrlDispatcherW
|
||||||
|
//sys SetServiceStatus(service Handle, serviceStatus *SERVICE_STATUS) (err error) = advapi32.SetServiceStatus
|
||||||
|
//sys ChangeServiceConfig(service Handle, serviceType uint32, startType uint32, errorControl uint32, binaryPathName *uint16, loadOrderGroup *uint16, tagId *uint32, dependencies *uint16, serviceStartName *uint16, password *uint16, displayName *uint16) (err error) = advapi32.ChangeServiceConfigW
|
||||||
|
//sys QueryServiceConfig(service Handle, serviceConfig *QUERY_SERVICE_CONFIG, bufSize uint32, bytesNeeded *uint32) (err error) = advapi32.QueryServiceConfigW
|
||||||
|
//sys ChangeServiceConfig2(service Handle, infoLevel uint32, info *byte) (err error) = advapi32.ChangeServiceConfig2W
|
||||||
|
//sys QueryServiceConfig2(service Handle, infoLevel uint32, buff *byte, buffSize uint32, bytesNeeded *uint32) (err error) = advapi32.QueryServiceConfig2W
|
|
@ -0,0 +1,22 @@
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
// +build windows
|
||||||
|
|
||||||
|
package windows
|
||||||
|
|
||||||
|
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,80 @@
|
||||||
|
// 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 windows
|
||||||
|
|
||||||
|
package eventlog
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
|
||||||
|
"golang.org/x/sys/windows"
|
||||||
|
"golang.org/x/sys/windows/registry"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// Log levels.
|
||||||
|
Info = windows.EVENTLOG_INFORMATION_TYPE
|
||||||
|
Warning = windows.EVENTLOG_WARNING_TYPE
|
||||||
|
Error = windows.EVENTLOG_ERROR_TYPE
|
||||||
|
)
|
||||||
|
|
||||||
|
const addKeyName = `SYSTEM\CurrentControlSet\Services\EventLog\Application`
|
||||||
|
|
||||||
|
// Install modifies PC registry to allow logging with an event source src.
|
||||||
|
// It adds all required keys and values to the event log registry key.
|
||||||
|
// Install uses msgFile as the event message file. If useExpandKey is true,
|
||||||
|
// the event message file is installed as REG_EXPAND_SZ value,
|
||||||
|
// otherwise as REG_SZ. Use bitwise of log.Error, log.Warning and
|
||||||
|
// log.Info to specify events supported by the new event source.
|
||||||
|
func Install(src, msgFile string, useExpandKey bool, eventsSupported uint32) error {
|
||||||
|
appkey, err := registry.OpenKey(registry.LOCAL_MACHINE, addKeyName, registry.CREATE_SUB_KEY)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer appkey.Close()
|
||||||
|
|
||||||
|
sk, alreadyExist, err := registry.CreateKey(appkey, src, registry.SET_VALUE)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer sk.Close()
|
||||||
|
if alreadyExist {
|
||||||
|
return errors.New(addKeyName + `\` + src + " registry key already exists")
|
||||||
|
}
|
||||||
|
|
||||||
|
err = sk.SetDWordValue("CustomSource", 1)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if useExpandKey {
|
||||||
|
err = sk.SetExpandStringValue("EventMessageFile", msgFile)
|
||||||
|
} else {
|
||||||
|
err = sk.SetStringValue("EventMessageFile", msgFile)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = sk.SetDWordValue("TypesSupported", eventsSupported)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// InstallAsEventCreate is the same as Install, but uses
|
||||||
|
// %SystemRoot%\System32\EventCreate.exe as the event message file.
|
||||||
|
func InstallAsEventCreate(src string, eventsSupported uint32) error {
|
||||||
|
return Install(src, "%SystemRoot%\\System32\\EventCreate.exe", true, eventsSupported)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove deletes all registry elements installed by the correspondent Install.
|
||||||
|
func Remove(src string) error {
|
||||||
|
appkey, err := registry.OpenKey(registry.LOCAL_MACHINE, addKeyName, registry.SET_VALUE)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer appkey.Close()
|
||||||
|
return registry.DeleteKey(appkey, src)
|
||||||
|
}
|
|
@ -0,0 +1,70 @@
|
||||||
|
// 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 windows
|
||||||
|
|
||||||
|
// Package eventlog implements access to Windows event log.
|
||||||
|
//
|
||||||
|
package eventlog
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"syscall"
|
||||||
|
|
||||||
|
"golang.org/x/sys/windows"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Log provides access to the system log.
|
||||||
|
type Log struct {
|
||||||
|
Handle windows.Handle
|
||||||
|
}
|
||||||
|
|
||||||
|
// Open retrieves a handle to the specified event log.
|
||||||
|
func Open(source string) (*Log, error) {
|
||||||
|
return OpenRemote("", source)
|
||||||
|
}
|
||||||
|
|
||||||
|
// OpenRemote does the same as Open, but on different computer host.
|
||||||
|
func OpenRemote(host, source string) (*Log, error) {
|
||||||
|
if source == "" {
|
||||||
|
return nil, errors.New("Specify event log source")
|
||||||
|
}
|
||||||
|
var s *uint16
|
||||||
|
if host != "" {
|
||||||
|
s = syscall.StringToUTF16Ptr(host)
|
||||||
|
}
|
||||||
|
h, err := windows.RegisterEventSource(s, syscall.StringToUTF16Ptr(source))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &Log{Handle: h}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close closes event log l.
|
||||||
|
func (l *Log) Close() error {
|
||||||
|
return windows.DeregisterEventSource(l.Handle)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *Log) report(etype uint16, eid uint32, msg string) error {
|
||||||
|
ss := []*uint16{syscall.StringToUTF16Ptr(msg)}
|
||||||
|
return windows.ReportEvent(l.Handle, etype, 0, eid, 0, 1, 0, &ss[0], nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Info writes an information event msg with event id eid to the end of event log l.
|
||||||
|
// When EventCreate.exe is used, eid must be between 1 and 1000.
|
||||||
|
func (l *Log) Info(eid uint32, msg string) error {
|
||||||
|
return l.report(windows.EVENTLOG_INFORMATION_TYPE, eid, msg)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Warning writes an warning event msg with event id eid to the end of event log l.
|
||||||
|
// When EventCreate.exe is used, eid must be between 1 and 1000.
|
||||||
|
func (l *Log) Warning(eid uint32, msg string) error {
|
||||||
|
return l.report(windows.EVENTLOG_WARNING_TYPE, eid, msg)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Error writes an error event msg with event id eid to the end of event log l.
|
||||||
|
// When EventCreate.exe is used, eid must be between 1 and 1000.
|
||||||
|
func (l *Log) Error(eid uint32, msg string) error {
|
||||||
|
return l.report(windows.EVENTLOG_ERROR_TYPE, eid, msg)
|
||||||
|
}
|
|
@ -0,0 +1,71 @@
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
// +build windows
|
||||||
|
|
||||||
|
// Package windows contains an interface to the low-level operating system
|
||||||
|
// primitives. OS details vary depending on the underlying system, and
|
||||||
|
// by default, godoc will display the OS-specific 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 this package 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 represents an operating system error describing the failure and
|
||||||
|
// holds a value of type syscall.Errno.
|
||||||
|
package windows // import "golang.org/x/sys/windows"
|
||||||
|
|
||||||
|
import (
|
||||||
|
"syscall"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 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, syscall.EINVAL).
|
||||||
|
func ByteSliceFromString(s string) ([]byte, error) {
|
||||||
|
for i := 0; i < len(s); i++ {
|
||||||
|
if s[i] == 0 {
|
||||||
|
return nil, syscall.EINVAL
|
||||||
|
}
|
||||||
|
}
|
||||||
|
a := make([]byte, len(s)+1)
|
||||||
|
copy(a, s)
|
||||||
|
return a, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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, syscall.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,989 @@
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
// Windows system calls.
|
||||||
|
|
||||||
|
package windows
|
||||||
|
|
||||||
|
import (
|
||||||
|
errorspkg "errors"
|
||||||
|
"sync"
|
||||||
|
"syscall"
|
||||||
|
"unicode/utf16"
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Handle uintptr
|
||||||
|
|
||||||
|
const InvalidHandle = ^Handle(0)
|
||||||
|
|
||||||
|
// StringToUTF16 is deprecated. Use UTF16FromString instead.
|
||||||
|
// If s contains a NUL byte this function panics instead of
|
||||||
|
// returning an error.
|
||||||
|
func StringToUTF16(s string) []uint16 {
|
||||||
|
a, err := UTF16FromString(s)
|
||||||
|
if err != nil {
|
||||||
|
panic("windows: string with NUL passed to StringToUTF16")
|
||||||
|
}
|
||||||
|
return a
|
||||||
|
}
|
||||||
|
|
||||||
|
// UTF16FromString returns the UTF-16 encoding of the UTF-8 string
|
||||||
|
// s, with a terminating NUL added. If s contains a NUL byte at any
|
||||||
|
// location, it returns (nil, syscall.EINVAL).
|
||||||
|
func UTF16FromString(s string) ([]uint16, error) {
|
||||||
|
for i := 0; i < len(s); i++ {
|
||||||
|
if s[i] == 0 {
|
||||||
|
return nil, syscall.EINVAL
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return utf16.Encode([]rune(s + "\x00")), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// UTF16ToString returns the UTF-8 encoding of the UTF-16 sequence s,
|
||||||
|
// with a terminating NUL removed.
|
||||||
|
func UTF16ToString(s []uint16) string {
|
||||||
|
for i, v := range s {
|
||||||
|
if v == 0 {
|
||||||
|
s = s[0:i]
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return string(utf16.Decode(s))
|
||||||
|
}
|
||||||
|
|
||||||
|
// StringToUTF16Ptr is deprecated. Use UTF16PtrFromString instead.
|
||||||
|
// If s contains a NUL byte this function panics instead of
|
||||||
|
// returning an error.
|
||||||
|
func StringToUTF16Ptr(s string) *uint16 { return &StringToUTF16(s)[0] }
|
||||||
|
|
||||||
|
// UTF16PtrFromString returns pointer to the UTF-16 encoding of
|
||||||
|
// the UTF-8 string s, with a terminating NUL added. If s
|
||||||
|
// contains a NUL byte at any location, it returns (nil, syscall.EINVAL).
|
||||||
|
func UTF16PtrFromString(s string) (*uint16, error) {
|
||||||
|
a, err := UTF16FromString(s)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &a[0], nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func Getpagesize() int { return 4096 }
|
||||||
|
|
||||||
|
// Converts a Go function to a function pointer conforming
|
||||||
|
// to the stdcall or cdecl calling convention. This is useful when
|
||||||
|
// interoperating with Windows code requiring callbacks.
|
||||||
|
// Implemented in runtime/syscall_windows.goc
|
||||||
|
func NewCallback(fn interface{}) uintptr
|
||||||
|
func NewCallbackCDecl(fn interface{}) uintptr
|
||||||
|
|
||||||
|
// windows api calls
|
||||||
|
|
||||||
|
//sys GetLastError() (lasterr error)
|
||||||
|
//sys LoadLibrary(libname string) (handle Handle, err error) = LoadLibraryW
|
||||||
|
//sys LoadLibraryEx(libname string, zero Handle, flags uintptr) (handle Handle, err error) = LoadLibraryExW
|
||||||
|
//sys FreeLibrary(handle Handle) (err error)
|
||||||
|
//sys GetProcAddress(module Handle, procname string) (proc uintptr, err error)
|
||||||
|
//sys GetVersion() (ver uint32, err error)
|
||||||
|
//sys FormatMessage(flags uint32, msgsrc uintptr, msgid uint32, langid uint32, buf []uint16, args *byte) (n uint32, err error) = FormatMessageW
|
||||||
|
//sys ExitProcess(exitcode uint32)
|
||||||
|
//sys CreateFile(name *uint16, access uint32, mode uint32, sa *SecurityAttributes, createmode uint32, attrs uint32, templatefile int32) (handle Handle, err error) [failretval==InvalidHandle] = CreateFileW
|
||||||
|
//sys ReadFile(handle Handle, buf []byte, done *uint32, overlapped *Overlapped) (err error)
|
||||||
|
//sys WriteFile(handle Handle, buf []byte, done *uint32, overlapped *Overlapped) (err error)
|
||||||
|
//sys SetFilePointer(handle Handle, lowoffset int32, highoffsetptr *int32, whence uint32) (newlowoffset uint32, err error) [failretval==0xffffffff]
|
||||||
|
//sys CloseHandle(handle Handle) (err error)
|
||||||
|
//sys GetStdHandle(stdhandle int) (handle Handle, err error) [failretval==InvalidHandle]
|
||||||
|
//sys findFirstFile1(name *uint16, data *win32finddata1) (handle Handle, err error) [failretval==InvalidHandle] = FindFirstFileW
|
||||||
|
//sys findNextFile1(handle Handle, data *win32finddata1) (err error) = FindNextFileW
|
||||||
|
//sys FindClose(handle Handle) (err error)
|
||||||
|
//sys GetFileInformationByHandle(handle Handle, data *ByHandleFileInformation) (err error)
|
||||||
|
//sys GetCurrentDirectory(buflen uint32, buf *uint16) (n uint32, err error) = GetCurrentDirectoryW
|
||||||
|
//sys SetCurrentDirectory(path *uint16) (err error) = SetCurrentDirectoryW
|
||||||
|
//sys CreateDirectory(path *uint16, sa *SecurityAttributes) (err error) = CreateDirectoryW
|
||||||
|
//sys RemoveDirectory(path *uint16) (err error) = RemoveDirectoryW
|
||||||
|
//sys DeleteFile(path *uint16) (err error) = DeleteFileW
|
||||||
|
//sys MoveFile(from *uint16, to *uint16) (err error) = MoveFileW
|
||||||
|
//sys MoveFileEx(from *uint16, to *uint16, flags uint32) (err error) = MoveFileExW
|
||||||
|
//sys GetComputerName(buf *uint16, n *uint32) (err error) = GetComputerNameW
|
||||||
|
//sys GetComputerNameEx(nametype uint32, buf *uint16, n *uint32) (err error) = GetComputerNameExW
|
||||||
|
//sys SetEndOfFile(handle Handle) (err error)
|
||||||
|
//sys GetSystemTimeAsFileTime(time *Filetime)
|
||||||
|
//sys GetTimeZoneInformation(tzi *Timezoneinformation) (rc uint32, err error) [failretval==0xffffffff]
|
||||||
|
//sys CreateIoCompletionPort(filehandle Handle, cphandle Handle, key uint32, threadcnt uint32) (handle Handle, err error)
|
||||||
|
//sys GetQueuedCompletionStatus(cphandle Handle, qty *uint32, key *uint32, overlapped **Overlapped, timeout uint32) (err error)
|
||||||
|
//sys PostQueuedCompletionStatus(cphandle Handle, qty uint32, key uint32, overlapped *Overlapped) (err error)
|
||||||
|
//sys CancelIo(s Handle) (err error)
|
||||||
|
//sys CancelIoEx(s Handle, o *Overlapped) (err error)
|
||||||
|
//sys CreateProcess(appName *uint16, commandLine *uint16, procSecurity *SecurityAttributes, threadSecurity *SecurityAttributes, inheritHandles bool, creationFlags uint32, env *uint16, currentDir *uint16, startupInfo *StartupInfo, outProcInfo *ProcessInformation) (err error) = CreateProcessW
|
||||||
|
//sys OpenProcess(da uint32, inheritHandle bool, pid uint32) (handle Handle, err error)
|
||||||
|
//sys TerminateProcess(handle Handle, exitcode uint32) (err error)
|
||||||
|
//sys GetExitCodeProcess(handle Handle, exitcode *uint32) (err error)
|
||||||
|
//sys GetStartupInfo(startupInfo *StartupInfo) (err error) = GetStartupInfoW
|
||||||
|
//sys GetCurrentProcess() (pseudoHandle Handle, err error)
|
||||||
|
//sys GetProcessTimes(handle Handle, creationTime *Filetime, exitTime *Filetime, kernelTime *Filetime, userTime *Filetime) (err error)
|
||||||
|
//sys DuplicateHandle(hSourceProcessHandle Handle, hSourceHandle Handle, hTargetProcessHandle Handle, lpTargetHandle *Handle, dwDesiredAccess uint32, bInheritHandle bool, dwOptions uint32) (err error)
|
||||||
|
//sys WaitForSingleObject(handle Handle, waitMilliseconds uint32) (event uint32, err error) [failretval==0xffffffff]
|
||||||
|
//sys GetTempPath(buflen uint32, buf *uint16) (n uint32, err error) = GetTempPathW
|
||||||
|
//sys CreatePipe(readhandle *Handle, writehandle *Handle, sa *SecurityAttributes, size uint32) (err error)
|
||||||
|
//sys GetFileType(filehandle Handle) (n uint32, err error)
|
||||||
|
//sys CryptAcquireContext(provhandle *Handle, container *uint16, provider *uint16, provtype uint32, flags uint32) (err error) = advapi32.CryptAcquireContextW
|
||||||
|
//sys CryptReleaseContext(provhandle Handle, flags uint32) (err error) = advapi32.CryptReleaseContext
|
||||||
|
//sys CryptGenRandom(provhandle Handle, buflen uint32, buf *byte) (err error) = advapi32.CryptGenRandom
|
||||||
|
//sys GetEnvironmentStrings() (envs *uint16, err error) [failretval==nil] = kernel32.GetEnvironmentStringsW
|
||||||
|
//sys FreeEnvironmentStrings(envs *uint16) (err error) = kernel32.FreeEnvironmentStringsW
|
||||||
|
//sys GetEnvironmentVariable(name *uint16, buffer *uint16, size uint32) (n uint32, err error) = kernel32.GetEnvironmentVariableW
|
||||||
|
//sys SetEnvironmentVariable(name *uint16, value *uint16) (err error) = kernel32.SetEnvironmentVariableW
|
||||||
|
//sys SetFileTime(handle Handle, ctime *Filetime, atime *Filetime, wtime *Filetime) (err error)
|
||||||
|
//sys GetFileAttributes(name *uint16) (attrs uint32, err error) [failretval==INVALID_FILE_ATTRIBUTES] = kernel32.GetFileAttributesW
|
||||||
|
//sys SetFileAttributes(name *uint16, attrs uint32) (err error) = kernel32.SetFileAttributesW
|
||||||
|
//sys GetFileAttributesEx(name *uint16, level uint32, info *byte) (err error) = kernel32.GetFileAttributesExW
|
||||||
|
//sys GetCommandLine() (cmd *uint16) = kernel32.GetCommandLineW
|
||||||
|
//sys CommandLineToArgv(cmd *uint16, argc *int32) (argv *[8192]*[8192]uint16, err error) [failretval==nil] = shell32.CommandLineToArgvW
|
||||||
|
//sys LocalFree(hmem Handle) (handle Handle, err error) [failretval!=0]
|
||||||
|
//sys SetHandleInformation(handle Handle, mask uint32, flags uint32) (err error)
|
||||||
|
//sys FlushFileBuffers(handle Handle) (err error)
|
||||||
|
//sys GetFullPathName(path *uint16, buflen uint32, buf *uint16, fname **uint16) (n uint32, err error) = kernel32.GetFullPathNameW
|
||||||
|
//sys GetLongPathName(path *uint16, buf *uint16, buflen uint32) (n uint32, err error) = kernel32.GetLongPathNameW
|
||||||
|
//sys GetShortPathName(longpath *uint16, shortpath *uint16, buflen uint32) (n uint32, err error) = kernel32.GetShortPathNameW
|
||||||
|
//sys CreateFileMapping(fhandle Handle, sa *SecurityAttributes, prot uint32, maxSizeHigh uint32, maxSizeLow uint32, name *uint16) (handle Handle, err error) = kernel32.CreateFileMappingW
|
||||||
|
//sys MapViewOfFile(handle Handle, access uint32, offsetHigh uint32, offsetLow uint32, length uintptr) (addr uintptr, err error)
|
||||||
|
//sys UnmapViewOfFile(addr uintptr) (err error)
|
||||||
|
//sys FlushViewOfFile(addr uintptr, length uintptr) (err error)
|
||||||
|
//sys VirtualLock(addr uintptr, length uintptr) (err error)
|
||||||
|
//sys VirtualUnlock(addr uintptr, length uintptr) (err error)
|
||||||
|
//sys TransmitFile(s Handle, handle Handle, bytesToWrite uint32, bytsPerSend uint32, overlapped *Overlapped, transmitFileBuf *TransmitFileBuffers, flags uint32) (err error) = mswsock.TransmitFile
|
||||||
|
//sys ReadDirectoryChanges(handle Handle, buf *byte, buflen uint32, watchSubTree bool, mask uint32, retlen *uint32, overlapped *Overlapped, completionRoutine uintptr) (err error) = kernel32.ReadDirectoryChangesW
|
||||||
|
//sys CertOpenSystemStore(hprov Handle, name *uint16) (store Handle, err error) = crypt32.CertOpenSystemStoreW
|
||||||
|
//sys CertOpenStore(storeProvider uintptr, msgAndCertEncodingType uint32, cryptProv uintptr, flags uint32, para uintptr) (handle Handle, err error) [failretval==InvalidHandle] = crypt32.CertOpenStore
|
||||||
|
//sys CertEnumCertificatesInStore(store Handle, prevContext *CertContext) (context *CertContext, err error) [failretval==nil] = crypt32.CertEnumCertificatesInStore
|
||||||
|
//sys CertAddCertificateContextToStore(store Handle, certContext *CertContext, addDisposition uint32, storeContext **CertContext) (err error) = crypt32.CertAddCertificateContextToStore
|
||||||
|
//sys CertCloseStore(store Handle, flags uint32) (err error) = crypt32.CertCloseStore
|
||||||
|
//sys CertGetCertificateChain(engine Handle, leaf *CertContext, time *Filetime, additionalStore Handle, para *CertChainPara, flags uint32, reserved uintptr, chainCtx **CertChainContext) (err error) = crypt32.CertGetCertificateChain
|
||||||
|
//sys CertFreeCertificateChain(ctx *CertChainContext) = crypt32.CertFreeCertificateChain
|
||||||
|
//sys CertCreateCertificateContext(certEncodingType uint32, certEncoded *byte, encodedLen uint32) (context *CertContext, err error) [failretval==nil] = crypt32.CertCreateCertificateContext
|
||||||
|
//sys CertFreeCertificateContext(ctx *CertContext) (err error) = crypt32.CertFreeCertificateContext
|
||||||
|
//sys CertVerifyCertificateChainPolicy(policyOID uintptr, chain *CertChainContext, para *CertChainPolicyPara, status *CertChainPolicyStatus) (err error) = crypt32.CertVerifyCertificateChainPolicy
|
||||||
|
//sys RegOpenKeyEx(key Handle, subkey *uint16, options uint32, desiredAccess uint32, result *Handle) (regerrno error) = advapi32.RegOpenKeyExW
|
||||||
|
//sys RegCloseKey(key Handle) (regerrno error) = advapi32.RegCloseKey
|
||||||
|
//sys RegQueryInfoKey(key Handle, class *uint16, classLen *uint32, reserved *uint32, subkeysLen *uint32, maxSubkeyLen *uint32, maxClassLen *uint32, valuesLen *uint32, maxValueNameLen *uint32, maxValueLen *uint32, saLen *uint32, lastWriteTime *Filetime) (regerrno error) = advapi32.RegQueryInfoKeyW
|
||||||
|
//sys RegEnumKeyEx(key Handle, index uint32, name *uint16, nameLen *uint32, reserved *uint32, class *uint16, classLen *uint32, lastWriteTime *Filetime) (regerrno error) = advapi32.RegEnumKeyExW
|
||||||
|
//sys RegQueryValueEx(key Handle, name *uint16, reserved *uint32, valtype *uint32, buf *byte, buflen *uint32) (regerrno error) = advapi32.RegQueryValueExW
|
||||||
|
//sys getCurrentProcessId() (pid uint32) = kernel32.GetCurrentProcessId
|
||||||
|
//sys GetConsoleMode(console Handle, mode *uint32) (err error) = kernel32.GetConsoleMode
|
||||||
|
//sys WriteConsole(console Handle, buf *uint16, towrite uint32, written *uint32, reserved *byte) (err error) = kernel32.WriteConsoleW
|
||||||
|
//sys ReadConsole(console Handle, buf *uint16, toread uint32, read *uint32, inputControl *byte) (err error) = kernel32.ReadConsoleW
|
||||||
|
//sys CreateToolhelp32Snapshot(flags uint32, processId uint32) (handle Handle, err error) [failretval==InvalidHandle] = kernel32.CreateToolhelp32Snapshot
|
||||||
|
//sys Process32First(snapshot Handle, procEntry *ProcessEntry32) (err error) = kernel32.Process32FirstW
|
||||||
|
//sys Process32Next(snapshot Handle, procEntry *ProcessEntry32) (err error) = kernel32.Process32NextW
|
||||||
|
//sys DeviceIoControl(handle Handle, ioControlCode uint32, inBuffer *byte, inBufferSize uint32, outBuffer *byte, outBufferSize uint32, bytesReturned *uint32, overlapped *Overlapped) (err error)
|
||||||
|
// This function returns 1 byte BOOLEAN rather than the 4 byte BOOL.
|
||||||
|
//sys CreateSymbolicLink(symlinkfilename *uint16, targetfilename *uint16, flags uint32) (err error) [failretval&0xff==0] = CreateSymbolicLinkW
|
||||||
|
//sys CreateHardLink(filename *uint16, existingfilename *uint16, reserved uintptr) (err error) [failretval&0xff==0] = CreateHardLinkW
|
||||||
|
//sys GetCurrentThreadId() (id uint32)
|
||||||
|
//sys CreateEvent(eventAttrs *syscall.SecurityAttributes, manualReset uint32, initialState uint32, name *uint16) (handle Handle, err error) = kernel32.CreateEventW
|
||||||
|
//sys SetEvent(event Handle) (err error) = kernel32.SetEvent
|
||||||
|
|
||||||
|
// syscall interface implementation for other packages
|
||||||
|
|
||||||
|
func Exit(code int) { ExitProcess(uint32(code)) }
|
||||||
|
|
||||||
|
func makeInheritSa() *SecurityAttributes {
|
||||||
|
var sa SecurityAttributes
|
||||||
|
sa.Length = uint32(unsafe.Sizeof(sa))
|
||||||
|
sa.InheritHandle = 1
|
||||||
|
return &sa
|
||||||
|
}
|
||||||
|
|
||||||
|
func Open(path string, mode int, perm uint32) (fd Handle, err error) {
|
||||||
|
if len(path) == 0 {
|
||||||
|
return InvalidHandle, ERROR_FILE_NOT_FOUND
|
||||||
|
}
|
||||||
|
pathp, err := UTF16PtrFromString(path)
|
||||||
|
if err != nil {
|
||||||
|
return InvalidHandle, err
|
||||||
|
}
|
||||||
|
var access uint32
|
||||||
|
switch mode & (O_RDONLY | O_WRONLY | O_RDWR) {
|
||||||
|
case O_RDONLY:
|
||||||
|
access = GENERIC_READ
|
||||||
|
case O_WRONLY:
|
||||||
|
access = GENERIC_WRITE
|
||||||
|
case O_RDWR:
|
||||||
|
access = GENERIC_READ | GENERIC_WRITE
|
||||||
|
}
|
||||||
|
if mode&O_CREAT != 0 {
|
||||||
|
access |= GENERIC_WRITE
|
||||||
|
}
|
||||||
|
if mode&O_APPEND != 0 {
|
||||||
|
access &^= GENERIC_WRITE
|
||||||
|
access |= FILE_APPEND_DATA
|
||||||
|
}
|
||||||
|
sharemode := uint32(FILE_SHARE_READ | FILE_SHARE_WRITE)
|
||||||
|
var sa *SecurityAttributes
|
||||||
|
if mode&O_CLOEXEC == 0 {
|
||||||
|
sa = makeInheritSa()
|
||||||
|
}
|
||||||
|
var createmode uint32
|
||||||
|
switch {
|
||||||
|
case mode&(O_CREAT|O_EXCL) == (O_CREAT | O_EXCL):
|
||||||
|
createmode = CREATE_NEW
|
||||||
|
case mode&(O_CREAT|O_TRUNC) == (O_CREAT | O_TRUNC):
|
||||||
|
createmode = CREATE_ALWAYS
|
||||||
|
case mode&O_CREAT == O_CREAT:
|
||||||
|
createmode = OPEN_ALWAYS
|
||||||
|
case mode&O_TRUNC == O_TRUNC:
|
||||||
|
createmode = TRUNCATE_EXISTING
|
||||||
|
default:
|
||||||
|
createmode = OPEN_EXISTING
|
||||||
|
}
|
||||||
|
h, e := CreateFile(pathp, access, sharemode, sa, createmode, FILE_ATTRIBUTE_NORMAL, 0)
|
||||||
|
return h, e
|
||||||
|
}
|
||||||
|
|
||||||
|
func Read(fd Handle, p []byte) (n int, err error) {
|
||||||
|
var done uint32
|
||||||
|
e := ReadFile(fd, p, &done, nil)
|
||||||
|
if e != nil {
|
||||||
|
if e == ERROR_BROKEN_PIPE {
|
||||||
|
// NOTE(brainman): work around ERROR_BROKEN_PIPE is returned on reading EOF from stdin
|
||||||
|
return 0, nil
|
||||||
|
}
|
||||||
|
return 0, e
|
||||||
|
}
|
||||||
|
if raceenabled {
|
||||||
|
if done > 0 {
|
||||||
|
raceWriteRange(unsafe.Pointer(&p[0]), int(done))
|
||||||
|
}
|
||||||
|
raceAcquire(unsafe.Pointer(&ioSync))
|
||||||
|
}
|
||||||
|
return int(done), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func Write(fd Handle, p []byte) (n int, err error) {
|
||||||
|
if raceenabled {
|
||||||
|
raceReleaseMerge(unsafe.Pointer(&ioSync))
|
||||||
|
}
|
||||||
|
var done uint32
|
||||||
|
e := WriteFile(fd, p, &done, nil)
|
||||||
|
if e != nil {
|
||||||
|
return 0, e
|
||||||
|
}
|
||||||
|
if raceenabled && done > 0 {
|
||||||
|
raceReadRange(unsafe.Pointer(&p[0]), int(done))
|
||||||
|
}
|
||||||
|
return int(done), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var ioSync int64
|
||||||
|
|
||||||
|
func Seek(fd Handle, offset int64, whence int) (newoffset int64, err error) {
|
||||||
|
var w uint32
|
||||||
|
switch whence {
|
||||||
|
case 0:
|
||||||
|
w = FILE_BEGIN
|
||||||
|
case 1:
|
||||||
|
w = FILE_CURRENT
|
||||||
|
case 2:
|
||||||
|
w = FILE_END
|
||||||
|
}
|
||||||
|
hi := int32(offset >> 32)
|
||||||
|
lo := int32(offset)
|
||||||
|
// use GetFileType to check pipe, pipe can't do seek
|
||||||
|
ft, _ := GetFileType(fd)
|
||||||
|
if ft == FILE_TYPE_PIPE {
|
||||||
|
return 0, syscall.EPIPE
|
||||||
|
}
|
||||||
|
rlo, e := SetFilePointer(fd, lo, &hi, w)
|
||||||
|
if e != nil {
|
||||||
|
return 0, e
|
||||||
|
}
|
||||||
|
return int64(hi)<<32 + int64(rlo), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func Close(fd Handle) (err error) {
|
||||||
|
return CloseHandle(fd)
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
Stdin = getStdHandle(STD_INPUT_HANDLE)
|
||||||
|
Stdout = getStdHandle(STD_OUTPUT_HANDLE)
|
||||||
|
Stderr = getStdHandle(STD_ERROR_HANDLE)
|
||||||
|
)
|
||||||
|
|
||||||
|
func getStdHandle(h int) (fd Handle) {
|
||||||
|
r, _ := GetStdHandle(h)
|
||||||
|
CloseOnExec(r)
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
|
const ImplementsGetwd = true
|
||||||
|
|
||||||
|
func Getwd() (wd string, err error) {
|
||||||
|
b := make([]uint16, 300)
|
||||||
|
n, e := GetCurrentDirectory(uint32(len(b)), &b[0])
|
||||||
|
if e != nil {
|
||||||
|
return "", e
|
||||||
|
}
|
||||||
|
return string(utf16.Decode(b[0:n])), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func Chdir(path string) (err error) {
|
||||||
|
pathp, err := UTF16PtrFromString(path)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return SetCurrentDirectory(pathp)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Mkdir(path string, mode uint32) (err error) {
|
||||||
|
pathp, err := UTF16PtrFromString(path)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return CreateDirectory(pathp, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Rmdir(path string) (err error) {
|
||||||
|
pathp, err := UTF16PtrFromString(path)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return RemoveDirectory(pathp)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Unlink(path string) (err error) {
|
||||||
|
pathp, err := UTF16PtrFromString(path)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return DeleteFile(pathp)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Rename(oldpath, newpath string) (err error) {
|
||||||
|
from, err := UTF16PtrFromString(oldpath)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
to, err := UTF16PtrFromString(newpath)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return MoveFileEx(from, to, MOVEFILE_REPLACE_EXISTING)
|
||||||
|
}
|
||||||
|
|
||||||
|
func ComputerName() (name string, err error) {
|
||||||
|
var n uint32 = MAX_COMPUTERNAME_LENGTH + 1
|
||||||
|
b := make([]uint16, n)
|
||||||
|
e := GetComputerName(&b[0], &n)
|
||||||
|
if e != nil {
|
||||||
|
return "", e
|
||||||
|
}
|
||||||
|
return string(utf16.Decode(b[0:n])), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func Ftruncate(fd Handle, length int64) (err error) {
|
||||||
|
curoffset, e := Seek(fd, 0, 1)
|
||||||
|
if e != nil {
|
||||||
|
return e
|
||||||
|
}
|
||||||
|
defer Seek(fd, curoffset, 0)
|
||||||
|
_, e = Seek(fd, length, 0)
|
||||||
|
if e != nil {
|
||||||
|
return e
|
||||||
|
}
|
||||||
|
e = SetEndOfFile(fd)
|
||||||
|
if e != nil {
|
||||||
|
return e
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func Gettimeofday(tv *Timeval) (err error) {
|
||||||
|
var ft Filetime
|
||||||
|
GetSystemTimeAsFileTime(&ft)
|
||||||
|
*tv = NsecToTimeval(ft.Nanoseconds())
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func Pipe(p []Handle) (err error) {
|
||||||
|
if len(p) != 2 {
|
||||||
|
return syscall.EINVAL
|
||||||
|
}
|
||||||
|
var r, w Handle
|
||||||
|
e := CreatePipe(&r, &w, makeInheritSa(), 0)
|
||||||
|
if e != nil {
|
||||||
|
return e
|
||||||
|
}
|
||||||
|
p[0] = r
|
||||||
|
p[1] = w
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func Utimes(path string, tv []Timeval) (err error) {
|
||||||
|
if len(tv) != 2 {
|
||||||
|
return syscall.EINVAL
|
||||||
|
}
|
||||||
|
pathp, e := UTF16PtrFromString(path)
|
||||||
|
if e != nil {
|
||||||
|
return e
|
||||||
|
}
|
||||||
|
h, e := CreateFile(pathp,
|
||||||
|
FILE_WRITE_ATTRIBUTES, FILE_SHARE_WRITE, nil,
|
||||||
|
OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0)
|
||||||
|
if e != nil {
|
||||||
|
return e
|
||||||
|
}
|
||||||
|
defer Close(h)
|
||||||
|
a := NsecToFiletime(tv[0].Nanoseconds())
|
||||||
|
w := NsecToFiletime(tv[1].Nanoseconds())
|
||||||
|
return SetFileTime(h, nil, &a, &w)
|
||||||
|
}
|
||||||
|
|
||||||
|
func UtimesNano(path string, ts []Timespec) (err error) {
|
||||||
|
if len(ts) != 2 {
|
||||||
|
return syscall.EINVAL
|
||||||
|
}
|
||||||
|
pathp, e := UTF16PtrFromString(path)
|
||||||
|
if e != nil {
|
||||||
|
return e
|
||||||
|
}
|
||||||
|
h, e := CreateFile(pathp,
|
||||||
|
FILE_WRITE_ATTRIBUTES, FILE_SHARE_WRITE, nil,
|
||||||
|
OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0)
|
||||||
|
if e != nil {
|
||||||
|
return e
|
||||||
|
}
|
||||||
|
defer Close(h)
|
||||||
|
a := NsecToFiletime(TimespecToNsec(ts[0]))
|
||||||
|
w := NsecToFiletime(TimespecToNsec(ts[1]))
|
||||||
|
return SetFileTime(h, nil, &a, &w)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Fsync(fd Handle) (err error) {
|
||||||
|
return FlushFileBuffers(fd)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Chmod(path string, mode uint32) (err error) {
|
||||||
|
if mode == 0 {
|
||||||
|
return syscall.EINVAL
|
||||||
|
}
|
||||||
|
p, e := UTF16PtrFromString(path)
|
||||||
|
if e != nil {
|
||||||
|
return e
|
||||||
|
}
|
||||||
|
attrs, e := GetFileAttributes(p)
|
||||||
|
if e != nil {
|
||||||
|
return e
|
||||||
|
}
|
||||||
|
if mode&S_IWRITE != 0 {
|
||||||
|
attrs &^= FILE_ATTRIBUTE_READONLY
|
||||||
|
} else {
|
||||||
|
attrs |= FILE_ATTRIBUTE_READONLY
|
||||||
|
}
|
||||||
|
return SetFileAttributes(p, attrs)
|
||||||
|
}
|
||||||
|
|
||||||
|
func LoadCancelIoEx() error {
|
||||||
|
return procCancelIoEx.Find()
|
||||||
|
}
|
||||||
|
|
||||||
|
func LoadSetFileCompletionNotificationModes() error {
|
||||||
|
return procSetFileCompletionNotificationModes.Find()
|
||||||
|
}
|
||||||
|
|
||||||
|
// net api calls
|
||||||
|
|
||||||
|
const socket_error = uintptr(^uint32(0))
|
||||||
|
|
||||||
|
//sys WSAStartup(verreq uint32, data *WSAData) (sockerr error) = ws2_32.WSAStartup
|
||||||
|
//sys WSACleanup() (err error) [failretval==socket_error] = ws2_32.WSACleanup
|
||||||
|
//sys WSAIoctl(s Handle, iocc uint32, inbuf *byte, cbif uint32, outbuf *byte, cbob uint32, cbbr *uint32, overlapped *Overlapped, completionRoutine uintptr) (err error) [failretval==socket_error] = ws2_32.WSAIoctl
|
||||||
|
//sys socket(af int32, typ int32, protocol int32) (handle Handle, err error) [failretval==InvalidHandle] = ws2_32.socket
|
||||||
|
//sys Setsockopt(s Handle, level int32, optname int32, optval *byte, optlen int32) (err error) [failretval==socket_error] = ws2_32.setsockopt
|
||||||
|
//sys Getsockopt(s Handle, level int32, optname int32, optval *byte, optlen *int32) (err error) [failretval==socket_error] = ws2_32.getsockopt
|
||||||
|
//sys bind(s Handle, name unsafe.Pointer, namelen int32) (err error) [failretval==socket_error] = ws2_32.bind
|
||||||
|
//sys connect(s Handle, name unsafe.Pointer, namelen int32) (err error) [failretval==socket_error] = ws2_32.connect
|
||||||
|
//sys getsockname(s Handle, rsa *RawSockaddrAny, addrlen *int32) (err error) [failretval==socket_error] = ws2_32.getsockname
|
||||||
|
//sys getpeername(s Handle, rsa *RawSockaddrAny, addrlen *int32) (err error) [failretval==socket_error] = ws2_32.getpeername
|
||||||
|
//sys listen(s Handle, backlog int32) (err error) [failretval==socket_error] = ws2_32.listen
|
||||||
|
//sys shutdown(s Handle, how int32) (err error) [failretval==socket_error] = ws2_32.shutdown
|
||||||
|
//sys Closesocket(s Handle) (err error) [failretval==socket_error] = ws2_32.closesocket
|
||||||
|
//sys AcceptEx(ls Handle, as Handle, buf *byte, rxdatalen uint32, laddrlen uint32, raddrlen uint32, recvd *uint32, overlapped *Overlapped) (err error) = mswsock.AcceptEx
|
||||||
|
//sys GetAcceptExSockaddrs(buf *byte, rxdatalen uint32, laddrlen uint32, raddrlen uint32, lrsa **RawSockaddrAny, lrsalen *int32, rrsa **RawSockaddrAny, rrsalen *int32) = mswsock.GetAcceptExSockaddrs
|
||||||
|
//sys WSARecv(s Handle, bufs *WSABuf, bufcnt uint32, recvd *uint32, flags *uint32, overlapped *Overlapped, croutine *byte) (err error) [failretval==socket_error] = ws2_32.WSARecv
|
||||||
|
//sys WSASend(s Handle, bufs *WSABuf, bufcnt uint32, sent *uint32, flags uint32, overlapped *Overlapped, croutine *byte) (err error) [failretval==socket_error] = ws2_32.WSASend
|
||||||
|
//sys WSARecvFrom(s Handle, bufs *WSABuf, bufcnt uint32, recvd *uint32, flags *uint32, from *RawSockaddrAny, fromlen *int32, overlapped *Overlapped, croutine *byte) (err error) [failretval==socket_error] = ws2_32.WSARecvFrom
|
||||||
|
//sys WSASendTo(s Handle, bufs *WSABuf, bufcnt uint32, sent *uint32, flags uint32, to *RawSockaddrAny, tolen int32, overlapped *Overlapped, croutine *byte) (err error) [failretval==socket_error] = ws2_32.WSASendTo
|
||||||
|
//sys GetHostByName(name string) (h *Hostent, err error) [failretval==nil] = ws2_32.gethostbyname
|
||||||
|
//sys GetServByName(name string, proto string) (s *Servent, err error) [failretval==nil] = ws2_32.getservbyname
|
||||||
|
//sys Ntohs(netshort uint16) (u uint16) = ws2_32.ntohs
|
||||||
|
//sys GetProtoByName(name string) (p *Protoent, err error) [failretval==nil] = ws2_32.getprotobyname
|
||||||
|
//sys DnsQuery(name string, qtype uint16, options uint32, extra *byte, qrs **DNSRecord, pr *byte) (status error) = dnsapi.DnsQuery_W
|
||||||
|
//sys DnsRecordListFree(rl *DNSRecord, freetype uint32) = dnsapi.DnsRecordListFree
|
||||||
|
//sys DnsNameCompare(name1 *uint16, name2 *uint16) (same bool) = dnsapi.DnsNameCompare_W
|
||||||
|
//sys GetAddrInfoW(nodename *uint16, servicename *uint16, hints *AddrinfoW, result **AddrinfoW) (sockerr error) = ws2_32.GetAddrInfoW
|
||||||
|
//sys FreeAddrInfoW(addrinfo *AddrinfoW) = ws2_32.FreeAddrInfoW
|
||||||
|
//sys GetIfEntry(pIfRow *MibIfRow) (errcode error) = iphlpapi.GetIfEntry
|
||||||
|
//sys GetAdaptersInfo(ai *IpAdapterInfo, ol *uint32) (errcode error) = iphlpapi.GetAdaptersInfo
|
||||||
|
//sys SetFileCompletionNotificationModes(handle Handle, flags uint8) (err error) = kernel32.SetFileCompletionNotificationModes
|
||||||
|
//sys WSAEnumProtocols(protocols *int32, protocolBuffer *WSAProtocolInfo, bufferLength *uint32) (n int32, err error) [failretval==-1] = ws2_32.WSAEnumProtocolsW
|
||||||
|
//sys GetAdaptersAddresses(family uint32, flags uint32, reserved uintptr, adapterAddresses *IpAdapterAddresses, sizePointer *uint32) (errcode error) = iphlpapi.GetAdaptersAddresses
|
||||||
|
//sys GetACP() (acp uint32) = kernel32.GetACP
|
||||||
|
//sys MultiByteToWideChar(codePage uint32, dwFlags uint32, str *byte, nstr int32, wchar *uint16, nwchar int32) (nwrite int32, err error) = kernel32.MultiByteToWideChar
|
||||||
|
|
||||||
|
// For testing: clients can set this flag to force
|
||||||
|
// creation of IPv6 sockets to return EAFNOSUPPORT.
|
||||||
|
var SocketDisableIPv6 bool
|
||||||
|
|
||||||
|
type RawSockaddrInet4 struct {
|
||||||
|
Family uint16
|
||||||
|
Port uint16
|
||||||
|
Addr [4]byte /* in_addr */
|
||||||
|
Zero [8]uint8
|
||||||
|
}
|
||||||
|
|
||||||
|
type RawSockaddrInet6 struct {
|
||||||
|
Family uint16
|
||||||
|
Port uint16
|
||||||
|
Flowinfo uint32
|
||||||
|
Addr [16]byte /* in6_addr */
|
||||||
|
Scope_id uint32
|
||||||
|
}
|
||||||
|
|
||||||
|
type RawSockaddr struct {
|
||||||
|
Family uint16
|
||||||
|
Data [14]int8
|
||||||
|
}
|
||||||
|
|
||||||
|
type RawSockaddrAny struct {
|
||||||
|
Addr RawSockaddr
|
||||||
|
Pad [96]int8
|
||||||
|
}
|
||||||
|
|
||||||
|
type Sockaddr interface {
|
||||||
|
sockaddr() (ptr unsafe.Pointer, len int32, err error) // lowercase; only we can define Sockaddrs
|
||||||
|
}
|
||||||
|
|
||||||
|
type SockaddrInet4 struct {
|
||||||
|
Port int
|
||||||
|
Addr [4]byte
|
||||||
|
raw RawSockaddrInet4
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sa *SockaddrInet4) sockaddr() (unsafe.Pointer, int32, error) {
|
||||||
|
if sa.Port < 0 || sa.Port > 0xFFFF {
|
||||||
|
return nil, 0, syscall.EINVAL
|
||||||
|
}
|
||||||
|
sa.raw.Family = AF_INET
|
||||||
|
p := (*[2]byte)(unsafe.Pointer(&sa.raw.Port))
|
||||||
|
p[0] = byte(sa.Port >> 8)
|
||||||
|
p[1] = byte(sa.Port)
|
||||||
|
for i := 0; i < len(sa.Addr); i++ {
|
||||||
|
sa.raw.Addr[i] = sa.Addr[i]
|
||||||
|
}
|
||||||
|
return unsafe.Pointer(&sa.raw), int32(unsafe.Sizeof(sa.raw)), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type SockaddrInet6 struct {
|
||||||
|
Port int
|
||||||
|
ZoneId uint32
|
||||||
|
Addr [16]byte
|
||||||
|
raw RawSockaddrInet6
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sa *SockaddrInet6) sockaddr() (unsafe.Pointer, int32, error) {
|
||||||
|
if sa.Port < 0 || sa.Port > 0xFFFF {
|
||||||
|
return nil, 0, syscall.EINVAL
|
||||||
|
}
|
||||||
|
sa.raw.Family = AF_INET6
|
||||||
|
p := (*[2]byte)(unsafe.Pointer(&sa.raw.Port))
|
||||||
|
p[0] = byte(sa.Port >> 8)
|
||||||
|
p[1] = byte(sa.Port)
|
||||||
|
sa.raw.Scope_id = sa.ZoneId
|
||||||
|
for i := 0; i < len(sa.Addr); i++ {
|
||||||
|
sa.raw.Addr[i] = sa.Addr[i]
|
||||||
|
}
|
||||||
|
return unsafe.Pointer(&sa.raw), int32(unsafe.Sizeof(sa.raw)), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type SockaddrUnix struct {
|
||||||
|
Name string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sa *SockaddrUnix) sockaddr() (unsafe.Pointer, int32, error) {
|
||||||
|
// TODO(brainman): implement SockaddrUnix.sockaddr()
|
||||||
|
return nil, 0, syscall.EWINDOWS
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rsa *RawSockaddrAny) Sockaddr() (Sockaddr, error) {
|
||||||
|
switch rsa.Addr.Family {
|
||||||
|
case AF_UNIX:
|
||||||
|
return nil, syscall.EWINDOWS
|
||||||
|
|
||||||
|
case AF_INET:
|
||||||
|
pp := (*RawSockaddrInet4)(unsafe.Pointer(rsa))
|
||||||
|
sa := new(SockaddrInet4)
|
||||||
|
p := (*[2]byte)(unsafe.Pointer(&pp.Port))
|
||||||
|
sa.Port = int(p[0])<<8 + int(p[1])
|
||||||
|
for i := 0; i < len(sa.Addr); i++ {
|
||||||
|
sa.Addr[i] = pp.Addr[i]
|
||||||
|
}
|
||||||
|
return sa, nil
|
||||||
|
|
||||||
|
case AF_INET6:
|
||||||
|
pp := (*RawSockaddrInet6)(unsafe.Pointer(rsa))
|
||||||
|
sa := new(SockaddrInet6)
|
||||||
|
p := (*[2]byte)(unsafe.Pointer(&pp.Port))
|
||||||
|
sa.Port = int(p[0])<<8 + int(p[1])
|
||||||
|
sa.ZoneId = pp.Scope_id
|
||||||
|
for i := 0; i < len(sa.Addr); i++ {
|
||||||
|
sa.Addr[i] = pp.Addr[i]
|
||||||
|
}
|
||||||
|
return sa, nil
|
||||||
|
}
|
||||||
|
return nil, syscall.EAFNOSUPPORT
|
||||||
|
}
|
||||||
|
|
||||||
|
func Socket(domain, typ, proto int) (fd Handle, err error) {
|
||||||
|
if domain == AF_INET6 && SocketDisableIPv6 {
|
||||||
|
return InvalidHandle, syscall.EAFNOSUPPORT
|
||||||
|
}
|
||||||
|
return socket(int32(domain), int32(typ), int32(proto))
|
||||||
|
}
|
||||||
|
|
||||||
|
func SetsockoptInt(fd Handle, level, opt int, value int) (err error) {
|
||||||
|
v := int32(value)
|
||||||
|
return Setsockopt(fd, int32(level), int32(opt), (*byte)(unsafe.Pointer(&v)), int32(unsafe.Sizeof(v)))
|
||||||
|
}
|
||||||
|
|
||||||
|
func Bind(fd Handle, sa Sockaddr) (err error) {
|
||||||
|
ptr, n, err := sa.sockaddr()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return bind(fd, ptr, n)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Connect(fd Handle, sa Sockaddr) (err error) {
|
||||||
|
ptr, n, err := sa.sockaddr()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return connect(fd, ptr, n)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Getsockname(fd Handle) (sa Sockaddr, err error) {
|
||||||
|
var rsa RawSockaddrAny
|
||||||
|
l := int32(unsafe.Sizeof(rsa))
|
||||||
|
if err = getsockname(fd, &rsa, &l); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return rsa.Sockaddr()
|
||||||
|
}
|
||||||
|
|
||||||
|
func Getpeername(fd Handle) (sa Sockaddr, err error) {
|
||||||
|
var rsa RawSockaddrAny
|
||||||
|
l := int32(unsafe.Sizeof(rsa))
|
||||||
|
if err = getpeername(fd, &rsa, &l); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return rsa.Sockaddr()
|
||||||
|
}
|
||||||
|
|
||||||
|
func Listen(s Handle, n int) (err error) {
|
||||||
|
return listen(s, int32(n))
|
||||||
|
}
|
||||||
|
|
||||||
|
func Shutdown(fd Handle, how int) (err error) {
|
||||||
|
return shutdown(fd, int32(how))
|
||||||
|
}
|
||||||
|
|
||||||
|
func WSASendto(s Handle, bufs *WSABuf, bufcnt uint32, sent *uint32, flags uint32, to Sockaddr, overlapped *Overlapped, croutine *byte) (err error) {
|
||||||
|
rsa, l, err := to.sockaddr()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return WSASendTo(s, bufs, bufcnt, sent, flags, (*RawSockaddrAny)(unsafe.Pointer(rsa)), l, overlapped, croutine)
|
||||||
|
}
|
||||||
|
|
||||||
|
func LoadGetAddrInfo() error {
|
||||||
|
return procGetAddrInfoW.Find()
|
||||||
|
}
|
||||||
|
|
||||||
|
var connectExFunc struct {
|
||||||
|
once sync.Once
|
||||||
|
addr uintptr
|
||||||
|
err error
|
||||||
|
}
|
||||||
|
|
||||||
|
func LoadConnectEx() error {
|
||||||
|
connectExFunc.once.Do(func() {
|
||||||
|
var s Handle
|
||||||
|
s, connectExFunc.err = Socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)
|
||||||
|
if connectExFunc.err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer CloseHandle(s)
|
||||||
|
var n uint32
|
||||||
|
connectExFunc.err = WSAIoctl(s,
|
||||||
|
SIO_GET_EXTENSION_FUNCTION_POINTER,
|
||||||
|
(*byte)(unsafe.Pointer(&WSAID_CONNECTEX)),
|
||||||
|
uint32(unsafe.Sizeof(WSAID_CONNECTEX)),
|
||||||
|
(*byte)(unsafe.Pointer(&connectExFunc.addr)),
|
||||||
|
uint32(unsafe.Sizeof(connectExFunc.addr)),
|
||||||
|
&n, nil, 0)
|
||||||
|
})
|
||||||
|
return connectExFunc.err
|
||||||
|
}
|
||||||
|
|
||||||
|
func connectEx(s Handle, name unsafe.Pointer, namelen int32, sendBuf *byte, sendDataLen uint32, bytesSent *uint32, overlapped *Overlapped) (err error) {
|
||||||
|
r1, _, e1 := syscall.Syscall9(connectExFunc.addr, 7, uintptr(s), uintptr(name), uintptr(namelen), uintptr(unsafe.Pointer(sendBuf)), uintptr(sendDataLen), uintptr(unsafe.Pointer(bytesSent)), uintptr(unsafe.Pointer(overlapped)), 0, 0)
|
||||||
|
if r1 == 0 {
|
||||||
|
if e1 != 0 {
|
||||||
|
err = error(e1)
|
||||||
|
} else {
|
||||||
|
err = syscall.EINVAL
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func ConnectEx(fd Handle, sa Sockaddr, sendBuf *byte, sendDataLen uint32, bytesSent *uint32, overlapped *Overlapped) error {
|
||||||
|
err := LoadConnectEx()
|
||||||
|
if err != nil {
|
||||||
|
return errorspkg.New("failed to find ConnectEx: " + err.Error())
|
||||||
|
}
|
||||||
|
ptr, n, err := sa.sockaddr()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return connectEx(fd, ptr, n, sendBuf, sendDataLen, bytesSent, overlapped)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Invented structures to support what package os expects.
|
||||||
|
type Rusage struct {
|
||||||
|
CreationTime Filetime
|
||||||
|
ExitTime Filetime
|
||||||
|
KernelTime Filetime
|
||||||
|
UserTime Filetime
|
||||||
|
}
|
||||||
|
|
||||||
|
type WaitStatus struct {
|
||||||
|
ExitCode uint32
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w WaitStatus) Exited() bool { return true }
|
||||||
|
|
||||||
|
func (w WaitStatus) ExitStatus() int { return int(w.ExitCode) }
|
||||||
|
|
||||||
|
func (w WaitStatus) Signal() Signal { return -1 }
|
||||||
|
|
||||||
|
func (w WaitStatus) CoreDump() bool { return false }
|
||||||
|
|
||||||
|
func (w WaitStatus) Stopped() bool { return false }
|
||||||
|
|
||||||
|
func (w WaitStatus) Continued() bool { return false }
|
||||||
|
|
||||||
|
func (w WaitStatus) StopSignal() Signal { return -1 }
|
||||||
|
|
||||||
|
func (w WaitStatus) Signaled() bool { return false }
|
||||||
|
|
||||||
|
func (w WaitStatus) TrapCause() int { return -1 }
|
||||||
|
|
||||||
|
// Timespec is an invented structure on Windows, but here for
|
||||||
|
// consistency with the corresponding package for other operating systems.
|
||||||
|
type Timespec struct {
|
||||||
|
Sec int64
|
||||||
|
Nsec int64
|
||||||
|
}
|
||||||
|
|
||||||
|
func TimespecToNsec(ts Timespec) int64 { return int64(ts.Sec)*1e9 + int64(ts.Nsec) }
|
||||||
|
|
||||||
|
func NsecToTimespec(nsec int64) (ts Timespec) {
|
||||||
|
ts.Sec = nsec / 1e9
|
||||||
|
ts.Nsec = nsec % 1e9
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO(brainman): fix all needed for net
|
||||||
|
|
||||||
|
func Accept(fd Handle) (nfd Handle, sa Sockaddr, err error) { return 0, nil, syscall.EWINDOWS }
|
||||||
|
func Recvfrom(fd Handle, p []byte, flags int) (n int, from Sockaddr, err error) {
|
||||||
|
return 0, nil, syscall.EWINDOWS
|
||||||
|
}
|
||||||
|
func Sendto(fd Handle, p []byte, flags int, to Sockaddr) (err error) { return syscall.EWINDOWS }
|
||||||
|
func SetsockoptTimeval(fd Handle, level, opt int, tv *Timeval) (err error) { return syscall.EWINDOWS }
|
||||||
|
|
||||||
|
// The Linger struct is wrong but we only noticed after Go 1.
|
||||||
|
// sysLinger is the real system call structure.
|
||||||
|
|
||||||
|
// BUG(brainman): The definition of Linger is not appropriate for direct use
|
||||||
|
// with Setsockopt and Getsockopt.
|
||||||
|
// Use SetsockoptLinger instead.
|
||||||
|
|
||||||
|
type Linger struct {
|
||||||
|
Onoff int32
|
||||||
|
Linger int32
|
||||||
|
}
|
||||||
|
|
||||||
|
type sysLinger struct {
|
||||||
|
Onoff uint16
|
||||||
|
Linger uint16
|
||||||
|
}
|
||||||
|
|
||||||
|
type IPMreq struct {
|
||||||
|
Multiaddr [4]byte /* in_addr */
|
||||||
|
Interface [4]byte /* in_addr */
|
||||||
|
}
|
||||||
|
|
||||||
|
type IPv6Mreq struct {
|
||||||
|
Multiaddr [16]byte /* in6_addr */
|
||||||
|
Interface uint32
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetsockoptInt(fd Handle, level, opt int) (int, error) { return -1, syscall.EWINDOWS }
|
||||||
|
|
||||||
|
func SetsockoptLinger(fd Handle, level, opt int, l *Linger) (err error) {
|
||||||
|
sys := sysLinger{Onoff: uint16(l.Onoff), Linger: uint16(l.Linger)}
|
||||||
|
return Setsockopt(fd, int32(level), int32(opt), (*byte)(unsafe.Pointer(&sys)), int32(unsafe.Sizeof(sys)))
|
||||||
|
}
|
||||||
|
|
||||||
|
func SetsockoptInet4Addr(fd Handle, level, opt int, value [4]byte) (err error) {
|
||||||
|
return Setsockopt(fd, int32(level), int32(opt), (*byte)(unsafe.Pointer(&value[0])), 4)
|
||||||
|
}
|
||||||
|
func SetsockoptIPMreq(fd Handle, level, opt int, mreq *IPMreq) (err error) {
|
||||||
|
return Setsockopt(fd, int32(level), int32(opt), (*byte)(unsafe.Pointer(mreq)), int32(unsafe.Sizeof(*mreq)))
|
||||||
|
}
|
||||||
|
func SetsockoptIPv6Mreq(fd Handle, level, opt int, mreq *IPv6Mreq) (err error) {
|
||||||
|
return syscall.EWINDOWS
|
||||||
|
}
|
||||||
|
|
||||||
|
func Getpid() (pid int) { return int(getCurrentProcessId()) }
|
||||||
|
|
||||||
|
func FindFirstFile(name *uint16, data *Win32finddata) (handle Handle, err error) {
|
||||||
|
// NOTE(rsc): The Win32finddata struct is wrong for the system call:
|
||||||
|
// the two paths are each one uint16 short. Use the correct struct,
|
||||||
|
// a win32finddata1, and then copy the results out.
|
||||||
|
// There is no loss of expressivity here, because the final
|
||||||
|
// uint16, if it is used, is supposed to be a NUL, and Go doesn't need that.
|
||||||
|
// For Go 1.1, we might avoid the allocation of win32finddata1 here
|
||||||
|
// by adding a final Bug [2]uint16 field to the struct and then
|
||||||
|
// adjusting the fields in the result directly.
|
||||||
|
var data1 win32finddata1
|
||||||
|
handle, err = findFirstFile1(name, &data1)
|
||||||
|
if err == nil {
|
||||||
|
copyFindData(data, &data1)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func FindNextFile(handle Handle, data *Win32finddata) (err error) {
|
||||||
|
var data1 win32finddata1
|
||||||
|
err = findNextFile1(handle, &data1)
|
||||||
|
if err == nil {
|
||||||
|
copyFindData(data, &data1)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func getProcessEntry(pid int) (*ProcessEntry32, error) {
|
||||||
|
snapshot, err := CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer CloseHandle(snapshot)
|
||||||
|
var procEntry ProcessEntry32
|
||||||
|
procEntry.Size = uint32(unsafe.Sizeof(procEntry))
|
||||||
|
if err = Process32First(snapshot, &procEntry); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
for {
|
||||||
|
if procEntry.ProcessID == uint32(pid) {
|
||||||
|
return &procEntry, nil
|
||||||
|
}
|
||||||
|
err = Process32Next(snapshot, &procEntry)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Getppid() (ppid int) {
|
||||||
|
pe, err := getProcessEntry(Getpid())
|
||||||
|
if err != nil {
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
return int(pe.ParentProcessID)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO(brainman): fix all needed for os
|
||||||
|
func Fchdir(fd Handle) (err error) { return syscall.EWINDOWS }
|
||||||
|
func Link(oldpath, newpath string) (err error) { return syscall.EWINDOWS }
|
||||||
|
func Symlink(path, link string) (err error) { return syscall.EWINDOWS }
|
||||||
|
|
||||||
|
func Fchmod(fd Handle, mode uint32) (err error) { return syscall.EWINDOWS }
|
||||||
|
func Chown(path string, uid int, gid int) (err error) { return syscall.EWINDOWS }
|
||||||
|
func Lchown(path string, uid int, gid int) (err error) { return syscall.EWINDOWS }
|
||||||
|
func Fchown(fd Handle, uid int, gid int) (err error) { return syscall.EWINDOWS }
|
||||||
|
|
||||||
|
func Getuid() (uid int) { return -1 }
|
||||||
|
func Geteuid() (euid int) { return -1 }
|
||||||
|
func Getgid() (gid int) { return -1 }
|
||||||
|
func Getegid() (egid int) { return -1 }
|
||||||
|
func Getgroups() (gids []int, err error) { return nil, syscall.EWINDOWS }
|
||||||
|
|
||||||
|
type Signal int
|
||||||
|
|
||||||
|
func (s Signal) Signal() {}
|
||||||
|
|
||||||
|
func (s Signal) String() string {
|
||||||
|
if 0 <= s && int(s) < len(signals) {
|
||||||
|
str := signals[s]
|
||||||
|
if str != "" {
|
||||||
|
return str
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return "signal " + itoa(int(s))
|
||||||
|
}
|
||||||
|
|
||||||
|
func LoadCreateSymbolicLink() error {
|
||||||
|
return procCreateSymbolicLinkW.Find()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Readlink returns the destination of the named symbolic link.
|
||||||
|
func Readlink(path string, buf []byte) (n int, err error) {
|
||||||
|
fd, err := CreateFile(StringToUTF16Ptr(path), GENERIC_READ, 0, nil, OPEN_EXISTING,
|
||||||
|
FILE_FLAG_OPEN_REPARSE_POINT|FILE_FLAG_BACKUP_SEMANTICS, 0)
|
||||||
|
if err != nil {
|
||||||
|
return -1, err
|
||||||
|
}
|
||||||
|
defer CloseHandle(fd)
|
||||||
|
|
||||||
|
rdbbuf := make([]byte, MAXIMUM_REPARSE_DATA_BUFFER_SIZE)
|
||||||
|
var bytesReturned uint32
|
||||||
|
err = DeviceIoControl(fd, FSCTL_GET_REPARSE_POINT, nil, 0, &rdbbuf[0], uint32(len(rdbbuf)), &bytesReturned, nil)
|
||||||
|
if err != nil {
|
||||||
|
return -1, err
|
||||||
|
}
|
||||||
|
|
||||||
|
rdb := (*reparseDataBuffer)(unsafe.Pointer(&rdbbuf[0]))
|
||||||
|
var s string
|
||||||
|
switch rdb.ReparseTag {
|
||||||
|
case IO_REPARSE_TAG_SYMLINK:
|
||||||
|
data := (*symbolicLinkReparseBuffer)(unsafe.Pointer(&rdb.reparseBuffer))
|
||||||
|
p := (*[0xffff]uint16)(unsafe.Pointer(&data.PathBuffer[0]))
|
||||||
|
s = UTF16ToString(p[data.PrintNameOffset/2 : (data.PrintNameLength-data.PrintNameOffset)/2])
|
||||||
|
case IO_REPARSE_TAG_MOUNT_POINT:
|
||||||
|
data := (*mountPointReparseBuffer)(unsafe.Pointer(&rdb.reparseBuffer))
|
||||||
|
p := (*[0xffff]uint16)(unsafe.Pointer(&data.PathBuffer[0]))
|
||||||
|
s = UTF16ToString(p[data.PrintNameOffset/2 : (data.PrintNameLength-data.PrintNameOffset)/2])
|
||||||
|
default:
|
||||||
|
// the path is not a symlink or junction but another type of reparse
|
||||||
|
// point
|
||||||
|
return -1, syscall.ENOENT
|
||||||
|
}
|
||||||
|
n = copy(buf, []byte(s))
|
||||||
|
|
||||||
|
return n, nil
|
||||||
|
}
|
File diff suppressed because it is too large
Load Diff
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 windows
|
||||||
|
|
||||||
|
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 windows
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
|
@ -106,6 +106,24 @@
|
||||||
"path": "golang.org/x/sys/unix",
|
"path": "golang.org/x/sys/unix",
|
||||||
"revision": "d75a52659825e75fff6158388dddc6a5b04f9ba5",
|
"revision": "d75a52659825e75fff6158388dddc6a5b04f9ba5",
|
||||||
"revisionTime": "2016-12-14T18:38:57Z"
|
"revisionTime": "2016-12-14T18:38:57Z"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"checksumSHA1": "kQB2wRB3twjUp615F6zEwGHjNe0=",
|
||||||
|
"path": "golang.org/x/sys/windows",
|
||||||
|
"revision": "d75a52659825e75fff6158388dddc6a5b04f9ba5",
|
||||||
|
"revisionTime": "2016-12-14T18:38:57Z"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"checksumSHA1": "ZdFZFaXmCgEEaEhVPkyXrnhKhsg=",
|
||||||
|
"path": "golang.org/x/sys/windows/registry",
|
||||||
|
"revision": "d75a52659825e75fff6158388dddc6a5b04f9ba5",
|
||||||
|
"revisionTime": "2016-12-14T18:38:57Z"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"checksumSHA1": "uVlUSSKplihZG7N+QJ6fzDZ4Kh8=",
|
||||||
|
"path": "golang.org/x/sys/windows/svc/eventlog",
|
||||||
|
"revision": "d75a52659825e75fff6158388dddc6a5b04f9ba5",
|
||||||
|
"revisionTime": "2016-12-14T18:38:57Z"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"rootPath": "github.com/prometheus/node_exporter"
|
"rootPath": "github.com/prometheus/node_exporter"
|
||||||
|
|
Loading…
Reference in New Issue