Windows: Support running dockerd as a service
This adds support for Windows dockerd to run as a Windows service, managed by the service control manager. The log is written to the Windows event log (and can be viewed in the event viewer or in PowerShell). If there is a Go panic, the stack is written to a file panic.log in the Docker root. Signed-off-by: John Starks <jostarks@microsoft.com>
This commit is contained in:
parent
4925fcbe2e
commit
57aef3b490
49 changed files with 8071 additions and 71 deletions
|
@ -1,5 +1,5 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
_ "github.com/docker/docker/autogen/winresources/dockerd"
|
||||
_ "github.com/docker/docker/autogen/winresources/docker"
|
||||
)
|
||||
|
|
|
@ -53,6 +53,9 @@ type DaemonCli struct {
|
|||
*daemon.Config
|
||||
commonFlags *cli.CommonFlags
|
||||
configFile *string
|
||||
|
||||
api *apiserver.Server
|
||||
d *daemon.Daemon
|
||||
}
|
||||
|
||||
func presentInHelp(usage string) string { return usage }
|
||||
|
@ -121,7 +124,10 @@ func migrateKey() (err error) {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (cli *DaemonCli) start() {
|
||||
func (cli *DaemonCli) start() (err error) {
|
||||
stopc := make(chan bool)
|
||||
defer close(stopc)
|
||||
|
||||
// warn from uuid package when running the daemon
|
||||
uuid.Loggerf = logrus.Warnf
|
||||
|
||||
|
@ -133,8 +139,7 @@ func (cli *DaemonCli) start() {
|
|||
}
|
||||
cliConfig, err := loadDaemonCliConfig(cli.Config, flags, cli.commonFlags, *cli.configFile)
|
||||
if err != nil {
|
||||
fmt.Fprint(os.Stderr, err)
|
||||
os.Exit(1)
|
||||
return err
|
||||
}
|
||||
cli.Config = cliConfig
|
||||
|
||||
|
@ -152,24 +157,22 @@ func (cli *DaemonCli) start() {
|
|||
})
|
||||
|
||||
if err := setDefaultUmask(); err != nil {
|
||||
logrus.Fatalf("Failed to set umask: %v", err)
|
||||
return fmt.Errorf("Failed to set umask: %v", err)
|
||||
}
|
||||
|
||||
if len(cli.LogConfig.Config) > 0 {
|
||||
if err := logger.ValidateLogOpts(cli.LogConfig.Type, cli.LogConfig.Config); err != nil {
|
||||
logrus.Fatalf("Failed to set log opts: %v", err)
|
||||
return fmt.Errorf("Failed to set log opts: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
var pfile *pidfile.PIDFile
|
||||
if cli.Pidfile != "" {
|
||||
pf, err := pidfile.New(cli.Pidfile)
|
||||
if err != nil {
|
||||
logrus.Fatalf("Error starting daemon: %v", err)
|
||||
return fmt.Errorf("Error starting daemon: %v", err)
|
||||
}
|
||||
pfile = pf
|
||||
defer func() {
|
||||
if err := pfile.Remove(); err != nil {
|
||||
if err := pf.Remove(); err != nil {
|
||||
logrus.Error(err)
|
||||
}
|
||||
}()
|
||||
|
@ -196,7 +199,7 @@ func (cli *DaemonCli) start() {
|
|||
}
|
||||
tlsConfig, err := tlsconfig.Server(tlsOptions)
|
||||
if err != nil {
|
||||
logrus.Fatal(err)
|
||||
return err
|
||||
}
|
||||
serverConfig.TLSConfig = tlsConfig
|
||||
}
|
||||
|
@ -210,13 +213,13 @@ func (cli *DaemonCli) start() {
|
|||
for i := 0; i < len(cli.Config.Hosts); i++ {
|
||||
var err error
|
||||
if cli.Config.Hosts[i], err = opts.ParseHost(cli.Config.TLS, cli.Config.Hosts[i]); err != nil {
|
||||
logrus.Fatalf("error parsing -H %s : %v", cli.Config.Hosts[i], err)
|
||||
return fmt.Errorf("error parsing -H %s : %v", cli.Config.Hosts[i], err)
|
||||
}
|
||||
|
||||
protoAddr := cli.Config.Hosts[i]
|
||||
protoAddrParts := strings.SplitN(protoAddr, "://", 2)
|
||||
if len(protoAddrParts) != 2 {
|
||||
logrus.Fatalf("bad format %s, expected PROTO://ADDR", protoAddr)
|
||||
return fmt.Errorf("bad format %s, expected PROTO://ADDR", protoAddr)
|
||||
}
|
||||
|
||||
proto := protoAddrParts[0]
|
||||
|
@ -228,12 +231,12 @@ func (cli *DaemonCli) start() {
|
|||
}
|
||||
l, err := listeners.Init(proto, addr, serverConfig.SocketGroup, serverConfig.TLSConfig)
|
||||
if err != nil {
|
||||
logrus.Fatal(err)
|
||||
return err
|
||||
}
|
||||
// If we're binding to a TCP port, make sure that a container doesn't try to use it.
|
||||
if proto == "tcp" {
|
||||
if err := allocateDaemonPort(addr); err != nil {
|
||||
logrus.Fatal(err)
|
||||
return err
|
||||
}
|
||||
}
|
||||
logrus.Debugf("Listener created for HTTP on %s (%s)", protoAddrParts[0], protoAddrParts[1])
|
||||
|
@ -241,24 +244,19 @@ func (cli *DaemonCli) start() {
|
|||
}
|
||||
|
||||
if err := migrateKey(); err != nil {
|
||||
logrus.Fatal(err)
|
||||
return err
|
||||
}
|
||||
cli.TrustKeyPath = cli.commonFlags.TrustKey
|
||||
|
||||
registryService := registry.NewService(cli.Config.ServiceOptions)
|
||||
containerdRemote, err := libcontainerd.New(cli.getLibcontainerdRoot(), cli.getPlatformRemoteOptions()...)
|
||||
if err != nil {
|
||||
logrus.Fatal(err)
|
||||
return err
|
||||
}
|
||||
|
||||
d, err := daemon.NewDaemon(cli.Config, registryService, containerdRemote)
|
||||
if err != nil {
|
||||
if pfile != nil {
|
||||
if err := pfile.Remove(); err != nil {
|
||||
logrus.Error(err)
|
||||
}
|
||||
}
|
||||
logrus.Fatalf("Error starting daemon: %v", err)
|
||||
return fmt.Errorf("Error starting daemon: %v", err)
|
||||
}
|
||||
|
||||
logrus.Info("Daemon has completed initialization")
|
||||
|
@ -272,26 +270,9 @@ func (cli *DaemonCli) start() {
|
|||
cli.initMiddlewares(api, serverConfig)
|
||||
initRouter(api, d)
|
||||
|
||||
reload := func(config *daemon.Config) {
|
||||
if err := d.Reload(config); err != nil {
|
||||
logrus.Errorf("Error reconfiguring the daemon: %v", err)
|
||||
return
|
||||
}
|
||||
if config.IsValueSet("debug") {
|
||||
debugEnabled := utils.IsDebugEnabled()
|
||||
switch {
|
||||
case debugEnabled && !config.Debug: // disable debug
|
||||
utils.DisableDebug()
|
||||
api.DisableProfiler()
|
||||
case config.Debug && !debugEnabled: // enable debug
|
||||
utils.EnableDebug()
|
||||
api.EnableProfiler()
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
setupConfigReloadTrap(*cli.configFile, flags, reload)
|
||||
cli.d = d
|
||||
cli.api = api
|
||||
cli.setupConfigReloadTrap()
|
||||
|
||||
// The serve API routine never exits unless an error occurs
|
||||
// We need to start it as a goroutine and wait on it so
|
||||
|
@ -300,14 +281,8 @@ func (cli *DaemonCli) start() {
|
|||
go api.Wait(serveAPIWait)
|
||||
|
||||
signal.Trap(func() {
|
||||
api.Close()
|
||||
<-serveAPIWait
|
||||
shutdownDaemon(d, 15)
|
||||
if pfile != nil {
|
||||
if err := pfile.Remove(); err != nil {
|
||||
logrus.Error(err)
|
||||
}
|
||||
}
|
||||
cli.stop()
|
||||
<-stopc // wait for daemonCli.start() to return
|
||||
})
|
||||
|
||||
// after the daemon is done setting up we can notify systemd api
|
||||
|
@ -319,13 +294,39 @@ func (cli *DaemonCli) start() {
|
|||
shutdownDaemon(d, 15)
|
||||
containerdRemote.Cleanup()
|
||||
if errAPI != nil {
|
||||
if pfile != nil {
|
||||
if err := pfile.Remove(); err != nil {
|
||||
logrus.Error(err)
|
||||
}
|
||||
}
|
||||
logrus.Fatalf("Shutting down due to ServeAPI error: %v", errAPI)
|
||||
return fmt.Errorf("Shutting down due to ServeAPI error: %v", errAPI)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (cli *DaemonCli) reloadConfig() {
|
||||
reload := func(config *daemon.Config) {
|
||||
if err := cli.d.Reload(config); err != nil {
|
||||
logrus.Errorf("Error reconfiguring the daemon: %v", err)
|
||||
return
|
||||
}
|
||||
if config.IsValueSet("debug") {
|
||||
debugEnabled := utils.IsDebugEnabled()
|
||||
switch {
|
||||
case debugEnabled && !config.Debug: // disable debug
|
||||
utils.DisableDebug()
|
||||
cli.api.DisableProfiler()
|
||||
case config.Debug && !debugEnabled: // enable debug
|
||||
utils.EnableDebug()
|
||||
cli.api.EnableProfiler()
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if err := daemon.ReloadConfiguration(*cli.configFile, flag.CommandLine, reload); err != nil {
|
||||
logrus.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
func (cli *DaemonCli) stop() {
|
||||
cli.api.Close()
|
||||
}
|
||||
|
||||
// shutdownDaemon just wraps daemon.Shutdown() to handle a timeout in case
|
||||
|
|
|
@ -11,10 +11,8 @@ import (
|
|||
"strconv"
|
||||
"syscall"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/docker/docker/daemon"
|
||||
"github.com/docker/docker/libcontainerd"
|
||||
"github.com/docker/docker/pkg/mflag"
|
||||
"github.com/docker/docker/pkg/system"
|
||||
"github.com/docker/libnetwork/portallocator"
|
||||
)
|
||||
|
@ -49,14 +47,12 @@ func getDaemonConfDir() string {
|
|||
}
|
||||
|
||||
// setupConfigReloadTrap configures the USR2 signal to reload the configuration.
|
||||
func setupConfigReloadTrap(configFile string, flags *mflag.FlagSet, reload func(*daemon.Config)) {
|
||||
func (cli *DaemonCli) setupConfigReloadTrap() {
|
||||
c := make(chan os.Signal, 1)
|
||||
signal.Notify(c, syscall.SIGHUP)
|
||||
go func() {
|
||||
for range c {
|
||||
if err := daemon.ReloadConfiguration(configFile, flags, reload); err != nil {
|
||||
logrus.Error(err)
|
||||
}
|
||||
cli.reloadConfig()
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
@ -111,3 +107,7 @@ func allocateDaemonPort(addr string) error {
|
|||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// notifyShutdown is called after the daemon shuts down but before the process exits.
|
||||
func notifyShutdown(err error) {
|
||||
}
|
||||
|
|
|
@ -6,9 +6,7 @@ import (
|
|||
"syscall"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/docker/docker/daemon"
|
||||
"github.com/docker/docker/libcontainerd"
|
||||
"github.com/docker/docker/pkg/mflag"
|
||||
"github.com/docker/docker/pkg/system"
|
||||
)
|
||||
|
||||
|
@ -31,10 +29,23 @@ func getDaemonConfDir() string {
|
|||
|
||||
// notifySystem sends a message to the host when the server is ready to be used
|
||||
func notifySystem() {
|
||||
if service != nil {
|
||||
err := service.started()
|
||||
if err != nil {
|
||||
logrus.Fatal(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// notifyShutdown is called after the daemon shuts down but before the process exits.
|
||||
func notifyShutdown(err error) {
|
||||
if service != nil {
|
||||
service.stopped(err)
|
||||
}
|
||||
}
|
||||
|
||||
// setupConfigReloadTrap configures a Win32 event to reload the configuration.
|
||||
func setupConfigReloadTrap(configFile string, flags *mflag.FlagSet, reload func(*daemon.Config)) {
|
||||
func (cli *DaemonCli) setupConfigReloadTrap() {
|
||||
go func() {
|
||||
sa := syscall.SecurityAttributes{
|
||||
Length: 0,
|
||||
|
@ -44,9 +55,7 @@ func setupConfigReloadTrap(configFile string, flags *mflag.FlagSet, reload func(
|
|||
logrus.Debugf("Config reload - waiting signal at %s", ev)
|
||||
for {
|
||||
syscall.WaitForSingleObject(h, syscall.INFINITE)
|
||||
if err := daemon.ReloadConfiguration(configFile, flags, reload); err != nil {
|
||||
logrus.Error(err)
|
||||
}
|
||||
cli.reloadConfig()
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
|
|
@ -56,7 +56,21 @@ func main() {
|
|||
flag.Usage()
|
||||
return
|
||||
}
|
||||
daemonCli.start()
|
||||
|
||||
// On Windows, this may be launching as a service or with an option to
|
||||
// register the service.
|
||||
stop, err := initService()
|
||||
if err != nil {
|
||||
logrus.Fatal(err)
|
||||
}
|
||||
|
||||
if !stop {
|
||||
err = daemonCli.start()
|
||||
notifyShutdown(err)
|
||||
if err != nil {
|
||||
logrus.Fatal(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func showVersion() {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
_ "github.com/docker/docker/autogen/winresources/docker"
|
||||
_ "github.com/docker/docker/autogen/winresources/dockerd"
|
||||
)
|
||||
|
|
7
cmd/dockerd/service_unsupported.go
Normal file
7
cmd/dockerd/service_unsupported.go
Normal file
|
@ -0,0 +1,7 @@
|
|||
// +build !windows
|
||||
|
||||
package main
|
||||
|
||||
func initService() (bool, error) {
|
||||
return false, nil
|
||||
}
|
369
cmd/dockerd/service_windows.go
Normal file
369
cmd/dockerd/service_windows.go
Normal file
|
@ -0,0 +1,369 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"syscall"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
flag "github.com/docker/docker/pkg/mflag"
|
||||
"golang.org/x/sys/windows"
|
||||
"golang.org/x/sys/windows/svc"
|
||||
"golang.org/x/sys/windows/svc/debug"
|
||||
"golang.org/x/sys/windows/svc/eventlog"
|
||||
"golang.org/x/sys/windows/svc/mgr"
|
||||
)
|
||||
|
||||
var (
|
||||
flServiceName = flag.String([]string{"-service-name"}, "docker", "Set the Windows service name")
|
||||
flRegisterService = flag.Bool([]string{"-register-service"}, false, "Register the service and exit")
|
||||
flUnregisterService = flag.Bool([]string{"-unregister-service"}, false, "Unregister the service and exit")
|
||||
flRunService = flag.Bool([]string{"-run-service"}, false, "")
|
||||
|
||||
setStdHandle = syscall.NewLazyDLL("kernel32.dll").NewProc("SetStdHandle")
|
||||
oldStderr syscall.Handle
|
||||
panicFile *os.File
|
||||
|
||||
service *handler
|
||||
)
|
||||
|
||||
const (
|
||||
// These should match the values in event_messages.mc.
|
||||
eventInfo = 1
|
||||
eventWarn = 1
|
||||
eventError = 1
|
||||
eventDebug = 2
|
||||
eventPanic = 3
|
||||
eventFatal = 4
|
||||
|
||||
eventExtraOffset = 10 // Add this to any event to get a string that supports extended data
|
||||
)
|
||||
|
||||
type handler struct {
|
||||
tosvc chan bool
|
||||
fromsvc chan error
|
||||
}
|
||||
|
||||
type etwHook struct {
|
||||
log *eventlog.Log
|
||||
}
|
||||
|
||||
func (h *etwHook) Levels() []logrus.Level {
|
||||
return []logrus.Level{
|
||||
logrus.PanicLevel,
|
||||
logrus.FatalLevel,
|
||||
logrus.ErrorLevel,
|
||||
logrus.WarnLevel,
|
||||
logrus.InfoLevel,
|
||||
logrus.DebugLevel,
|
||||
}
|
||||
}
|
||||
|
||||
func (h *etwHook) Fire(e *logrus.Entry) error {
|
||||
var (
|
||||
etype uint16
|
||||
eid uint32
|
||||
)
|
||||
|
||||
switch e.Level {
|
||||
case logrus.PanicLevel:
|
||||
etype = windows.EVENTLOG_ERROR_TYPE
|
||||
eid = eventPanic
|
||||
case logrus.FatalLevel:
|
||||
etype = windows.EVENTLOG_ERROR_TYPE
|
||||
eid = eventFatal
|
||||
case logrus.ErrorLevel:
|
||||
etype = windows.EVENTLOG_ERROR_TYPE
|
||||
eid = eventError
|
||||
case logrus.WarnLevel:
|
||||
etype = windows.EVENTLOG_WARNING_TYPE
|
||||
eid = eventWarn
|
||||
case logrus.InfoLevel:
|
||||
etype = windows.EVENTLOG_INFORMATION_TYPE
|
||||
eid = eventInfo
|
||||
case logrus.DebugLevel:
|
||||
etype = windows.EVENTLOG_INFORMATION_TYPE
|
||||
eid = eventDebug
|
||||
default:
|
||||
return errors.New("unknown level")
|
||||
}
|
||||
|
||||
// If there is additional data, include it as a second string.
|
||||
exts := ""
|
||||
if len(e.Data) > 0 {
|
||||
fs := bytes.Buffer{}
|
||||
for k, v := range e.Data {
|
||||
fs.WriteString(k)
|
||||
fs.WriteByte('=')
|
||||
fmt.Fprint(&fs, v)
|
||||
fs.WriteByte(' ')
|
||||
}
|
||||
|
||||
exts = fs.String()[:fs.Len()-1]
|
||||
eid += eventExtraOffset
|
||||
}
|
||||
|
||||
if h.log == nil {
|
||||
fmt.Fprintf(os.Stderr, "%s [%s]\n", e.Message, exts)
|
||||
return nil
|
||||
}
|
||||
|
||||
var (
|
||||
ss [2]*uint16
|
||||
err error
|
||||
)
|
||||
|
||||
ss[0], err = syscall.UTF16PtrFromString(e.Message)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
count := uint16(1)
|
||||
if exts != "" {
|
||||
ss[1], err = syscall.UTF16PtrFromString(exts)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
count++
|
||||
}
|
||||
|
||||
return windows.ReportEvent(h.log.Handle, etype, 0, eid, 0, count, 0, &ss[0], nil)
|
||||
}
|
||||
|
||||
func getServicePath() (string, error) {
|
||||
p, err := exec.LookPath(os.Args[0])
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return filepath.Abs(p)
|
||||
}
|
||||
|
||||
func registerService() error {
|
||||
p, err := getServicePath()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
m, err := mgr.Connect()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer m.Disconnect()
|
||||
c := mgr.Config{
|
||||
ServiceType: windows.SERVICE_WIN32_OWN_PROCESS,
|
||||
StartType: mgr.StartAutomatic,
|
||||
ErrorControl: mgr.ErrorNormal,
|
||||
DisplayName: "Docker Engine",
|
||||
}
|
||||
|
||||
// Configure the service to launch with the arguments that were just passed.
|
||||
args := []string{"--run-service"}
|
||||
for _, a := range os.Args[1:] {
|
||||
if a != "--register-service" && a != "--unregister-service" {
|
||||
args = append(args, a)
|
||||
}
|
||||
}
|
||||
|
||||
s, err := m.CreateService(*flServiceName, p, c, args...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer s.Close()
|
||||
err = eventlog.Install(*flServiceName, p, false, eventlog.Info|eventlog.Warning|eventlog.Error)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func unregisterService() error {
|
||||
m, err := mgr.Connect()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer m.Disconnect()
|
||||
|
||||
s, err := m.OpenService(*flServiceName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer s.Close()
|
||||
|
||||
eventlog.Remove(*flServiceName)
|
||||
err = s.Delete()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func initService() (bool, error) {
|
||||
if *flUnregisterService {
|
||||
if *flRegisterService {
|
||||
return true, errors.New("--register-service and --unregister-service cannot be used together")
|
||||
}
|
||||
return true, unregisterService()
|
||||
}
|
||||
|
||||
if *flRegisterService {
|
||||
return true, registerService()
|
||||
}
|
||||
|
||||
if !*flRunService {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
interactive, err := svc.IsAnInteractiveSession()
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
h := &handler{
|
||||
tosvc: make(chan bool),
|
||||
fromsvc: make(chan error),
|
||||
}
|
||||
|
||||
var log *eventlog.Log
|
||||
if !interactive {
|
||||
log, err = eventlog.Open(*flServiceName)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
}
|
||||
|
||||
logrus.AddHook(&etwHook{log})
|
||||
logrus.SetOutput(ioutil.Discard)
|
||||
|
||||
service = h
|
||||
go func() {
|
||||
if interactive {
|
||||
err = debug.Run(*flServiceName, h)
|
||||
} else {
|
||||
err = svc.Run(*flServiceName, h)
|
||||
}
|
||||
|
||||
h.fromsvc <- err
|
||||
}()
|
||||
|
||||
// Wait for the first signal from the service handler.
|
||||
err = <-h.fromsvc
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
return false, nil
|
||||
}
|
||||
|
||||
func (h *handler) started() error {
|
||||
// This must be delayed until daemonCli initializes Config.Root
|
||||
err := initPanicFile(filepath.Join(daemonCli.Config.Root, "panic.log"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
h.tosvc <- false
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *handler) stopped(err error) {
|
||||
logrus.Debugf("Stopping service: %v", err)
|
||||
h.tosvc <- err != nil
|
||||
<-h.fromsvc
|
||||
}
|
||||
|
||||
func (h *handler) Execute(_ []string, r <-chan svc.ChangeRequest, s chan<- svc.Status) (bool, uint32) {
|
||||
s <- svc.Status{State: svc.StartPending, Accepts: 0}
|
||||
// Unblock initService()
|
||||
h.fromsvc <- nil
|
||||
|
||||
// Wait for initialization to complete.
|
||||
failed := <-h.tosvc
|
||||
if failed {
|
||||
logrus.Debugf("Aborting service start due to failure during initializtion")
|
||||
return true, 1
|
||||
}
|
||||
|
||||
s <- svc.Status{State: svc.Running, Accepts: svc.AcceptStop | svc.AcceptShutdown | svc.Accepted(windows.SERVICE_ACCEPT_PARAMCHANGE)}
|
||||
logrus.Debugf("Service running")
|
||||
Loop:
|
||||
for {
|
||||
select {
|
||||
case failed = <-h.tosvc:
|
||||
break Loop
|
||||
case c := <-r:
|
||||
switch c.Cmd {
|
||||
case svc.Cmd(windows.SERVICE_CONTROL_PARAMCHANGE):
|
||||
daemonCli.reloadConfig()
|
||||
case svc.Interrogate:
|
||||
s <- c.CurrentStatus
|
||||
case svc.Stop, svc.Shutdown:
|
||||
s <- svc.Status{State: svc.StopPending, Accepts: 0}
|
||||
daemonCli.stop()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
removePanicFile()
|
||||
if failed {
|
||||
return true, 1
|
||||
}
|
||||
return false, 0
|
||||
}
|
||||
|
||||
func initPanicFile(path string) error {
|
||||
var err error
|
||||
panicFile, err = os.OpenFile(path, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
st, err := panicFile.Stat()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// If there are contents in the file already, move the file out of the way
|
||||
// and replace it.
|
||||
if st.Size() > 0 {
|
||||
panicFile.Close()
|
||||
os.Rename(path, path+".old")
|
||||
panicFile, err = os.Create(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// Update STD_ERROR_HANDLE to point to the panic file so that Go writes to
|
||||
// it when it panics. Remember the old stderr to restore it before removing
|
||||
// the panic file.
|
||||
sh := syscall.STD_ERROR_HANDLE
|
||||
h, err := syscall.GetStdHandle(sh)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
oldStderr = h
|
||||
|
||||
r, _, err := setStdHandle.Call(uintptr(sh), uintptr(panicFile.Fd()))
|
||||
if r == 0 && err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func removePanicFile() {
|
||||
if st, err := panicFile.Stat(); err == nil {
|
||||
if st.Size() == 0 {
|
||||
sh := syscall.STD_ERROR_HANDLE
|
||||
setStdHandle.Call(uintptr(sh), uintptr(oldStderr))
|
||||
panicFile.Close()
|
||||
os.Remove(panicFile.Name())
|
||||
}
|
||||
}
|
||||
}
|
|
@ -27,9 +27,11 @@ if [ "$(go env GOOS)" = "windows" ]; then
|
|||
|
||||
if [ "$(go env GOHOSTOS)" == "windows" ]; then
|
||||
WINDRES=windres
|
||||
WINDMC=windmc
|
||||
else
|
||||
# Cross compiling
|
||||
WINDRES=x86_64-w64-mingw32-windres
|
||||
WINDMC=x86_64-w64-mingw32-windmc
|
||||
fi
|
||||
|
||||
# Generate a Windows file version of the form major,minor,patch,build (with any part optional)
|
||||
|
@ -51,6 +53,11 @@ if [ "$(go env GOOS)" = "windows" ]; then
|
|||
$defs
|
||||
}
|
||||
|
||||
$WINDMC \
|
||||
hack/make/.resources-windows/event_messages.mc \
|
||||
-h autogen/winresources/tmp \
|
||||
-r autogen/winresources/tmp
|
||||
|
||||
makeres docker.rc pe-x86-64 autogen/winresources/docker/rsrc_amd64.syso
|
||||
makeres docker.rc pe-i386 autogen/winresources/docker/rsrc_386.syso
|
||||
makeres dockerd.rc pe-x86-64 autogen/winresources/dockerd/rsrc_amd64.syso
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
#define DOCKER_NAME "Docker Engine"
|
||||
|
||||
#include "common.rc"
|
||||
#include "event_messages.rc"
|
||||
|
|
39
hack/make/.resources-windows/event_messages.mc
Normal file
39
hack/make/.resources-windows/event_messages.mc
Normal file
|
@ -0,0 +1,39 @@
|
|||
MessageId=1
|
||||
Language=English
|
||||
%1
|
||||
.
|
||||
|
||||
MessageId=2
|
||||
Language=English
|
||||
debug: %1
|
||||
.
|
||||
|
||||
MessageId=3
|
||||
Language=English
|
||||
panic: %1
|
||||
.
|
||||
|
||||
MessageId=4
|
||||
Language=English
|
||||
fatal: %1
|
||||
.
|
||||
|
||||
MessageId=11
|
||||
Language=English
|
||||
%1 [%2]
|
||||
.
|
||||
|
||||
MessageId=12
|
||||
Language=English
|
||||
debug: %1 [%2]
|
||||
.
|
||||
|
||||
MessageId=13
|
||||
Language=English
|
||||
panic: %1 [%2]
|
||||
.
|
||||
|
||||
MessageId=14
|
||||
Language=English
|
||||
fatal: %1 [%2]
|
||||
.
|
8
vendor/src/golang.org/x/sys/windows/asm.s
vendored
Normal file
8
vendor/src/golang.org/x/sys/windows/asm.s
vendored
Normal file
|
@ -0,0 +1,8 @@
|
|||
// 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.
|
||||
|
||||
#include "textflag.h"
|
||||
|
||||
TEXT ·use(SB),NOSPLIT,$0
|
||||
RET
|
13
vendor/src/golang.org/x/sys/windows/asm_windows_386.s
vendored
Normal file
13
vendor/src/golang.org/x/sys/windows/asm_windows_386.s
vendored
Normal file
|
@ -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)
|
13
vendor/src/golang.org/x/sys/windows/asm_windows_amd64.s
vendored
Normal file
13
vendor/src/golang.org/x/sys/windows/asm_windows_amd64.s
vendored
Normal file
|
@ -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)
|
275
vendor/src/golang.org/x/sys/windows/dll_windows.go
vendored
Normal file
275
vendor/src/golang.org/x/sys/windows/dll_windows.go
vendored
Normal file
|
@ -0,0 +1,275 @@
|
|||
// 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.
|
||||
func LoadDLL(name string) (dll *DLL, err error) {
|
||||
namep, err := UTF16PtrFromString(name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
h, e := loadlibrary(namep)
|
||||
if e != 0 {
|
||||
return nil, &DLLError{
|
||||
Err: e,
|
||||
ObjName: name,
|
||||
Msg: "Failed to load " + name + ": " + e.Error(),
|
||||
}
|
||||
}
|
||||
d := &DLL{
|
||||
Name: name,
|
||||
Handle: Handle(h),
|
||||
}
|
||||
return d, nil
|
||||
}
|
||||
|
||||
// MustLoadDLL is like LoadDLL but panics if load operation failes.
|
||||
func MustLoadDLL(name string) *DLL {
|
||||
d, e := LoadDLL(name)
|
||||
if e != nil {
|
||||
panic(e)
|
||||
}
|
||||
return d
|
||||
}
|
||||
|
||||
// FindProc searches DLL d for procedure named name and returns *Proc
|
||||
// if found. It returns an error if search fails.
|
||||
func (d *DLL) FindProc(name string) (proc *Proc, err error) {
|
||||
namep, err := BytePtrFromString(name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
a, e := getprocaddress(uintptr(d.Handle), namep)
|
||||
if e != 0 {
|
||||
return nil, &DLLError{
|
||||
Err: e,
|
||||
ObjName: name,
|
||||
Msg: "Failed to find " + name + " procedure in " + d.Name + ": " + e.Error(),
|
||||
}
|
||||
}
|
||||
p := &Proc{
|
||||
Dll: d,
|
||||
Name: name,
|
||||
addr: a,
|
||||
}
|
||||
return p, nil
|
||||
}
|
||||
|
||||
// MustFindProc is like FindProc but panics if search fails.
|
||||
func (d *DLL) MustFindProc(name string) *Proc {
|
||||
p, e := d.FindProc(name)
|
||||
if e != nil {
|
||||
panic(e)
|
||||
}
|
||||
return p
|
||||
}
|
||||
|
||||
// Release unloads DLL d from memory.
|
||||
func (d *DLL) Release() (err error) {
|
||||
return FreeLibrary(d.Handle)
|
||||
}
|
||||
|
||||
// A Proc implements access to a procedure inside a DLL.
|
||||
type Proc struct {
|
||||
Dll *DLL
|
||||
Name string
|
||||
addr uintptr
|
||||
}
|
||||
|
||||
// Addr returns the address of the procedure represented by p.
|
||||
// The return value can be passed to Syscall to run the procedure.
|
||||
func (p *Proc) Addr() uintptr {
|
||||
return p.addr
|
||||
}
|
||||
|
||||
// Call executes procedure p with arguments a. It will panic, if more then 15 arguments
|
||||
// are supplied.
|
||||
//
|
||||
// The returned error is always non-nil, constructed from the result of GetLastError.
|
||||
// Callers must inspect the primary return value to decide whether an error occurred
|
||||
// (according to the semantics of the specific function being called) before consulting
|
||||
// the error. The error will be guaranteed to contain 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 {
|
||||
mu sync.Mutex
|
||||
dll *DLL // non nil once DLL is loaded
|
||||
Name string
|
||||
}
|
||||
|
||||
// Load loads DLL file d.Name into memory. It returns an error if fails.
|
||||
// Load will not try to load DLL, if it is already loaded into memory.
|
||||
func (d *LazyDLL) Load() error {
|
||||
// Non-racy version of:
|
||||
// if d.dll == nil {
|
||||
if atomic.LoadPointer((*unsafe.Pointer)(unsafe.Pointer(&d.dll))) == nil {
|
||||
d.mu.Lock()
|
||||
defer d.mu.Unlock()
|
||||
if d.dll == nil {
|
||||
dll, e := LoadDLL(d.Name)
|
||||
if e != nil {
|
||||
return e
|
||||
}
|
||||
// Non-racy version of:
|
||||
// d.dll = dll
|
||||
atomic.StorePointer((*unsafe.Pointer)(unsafe.Pointer(&d.dll)), unsafe.Pointer(dll))
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// mustLoad is like Load but panics if search fails.
|
||||
func (d *LazyDLL) mustLoad() {
|
||||
e := d.Load()
|
||||
if e != nil {
|
||||
panic(e)
|
||||
}
|
||||
}
|
||||
|
||||
// Handle returns d's module handle.
|
||||
func (d *LazyDLL) Handle() uintptr {
|
||||
d.mustLoad()
|
||||
return uintptr(d.dll.Handle)
|
||||
}
|
||||
|
||||
// NewProc returns a LazyProc for accessing the named procedure in the DLL d.
|
||||
func (d *LazyDLL) NewProc(name string) *LazyProc {
|
||||
return &LazyProc{l: d, Name: name}
|
||||
}
|
||||
|
||||
// NewLazyDLL creates new LazyDLL associated with DLL file.
|
||||
func NewLazyDLL(name string) *LazyDLL {
|
||||
return &LazyDLL{Name: name}
|
||||
}
|
||||
|
||||
// A LazyProc implements access to a procedure inside a LazyDLL.
|
||||
// It delays the lookup until the Addr method is called.
|
||||
type LazyProc struct {
|
||||
mu sync.Mutex
|
||||
Name string
|
||||
l *LazyDLL
|
||||
proc *Proc
|
||||
}
|
||||
|
||||
// Find searches DLL for procedure named p.Name. It returns
|
||||
// an error if search fails. Find will not search procedure,
|
||||
// if it is already found and loaded into memory.
|
||||
func (p *LazyProc) Find() error {
|
||||
// Non-racy version of:
|
||||
// if p.proc == nil {
|
||||
if atomic.LoadPointer((*unsafe.Pointer)(unsafe.Pointer(&p.proc))) == nil {
|
||||
p.mu.Lock()
|
||||
defer p.mu.Unlock()
|
||||
if p.proc == nil {
|
||||
e := p.l.Load()
|
||||
if e != nil {
|
||||
return e
|
||||
}
|
||||
proc, e := p.l.dll.FindProc(p.Name)
|
||||
if e != nil {
|
||||
return e
|
||||
}
|
||||
// Non-racy version of:
|
||||
// p.proc = proc
|
||||
atomic.StorePointer((*unsafe.Pointer)(unsafe.Pointer(&p.proc)), unsafe.Pointer(proc))
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// mustFind is like Find but panics if search fails.
|
||||
func (p *LazyProc) mustFind() {
|
||||
e := p.Find()
|
||||
if e != nil {
|
||||
panic(e)
|
||||
}
|
||||
}
|
||||
|
||||
// Addr returns the address of the procedure represented by p.
|
||||
// The return value can be passed to Syscall to run the procedure.
|
||||
func (p *LazyProc) Addr() uintptr {
|
||||
p.mustFind()
|
||||
return p.proc.Addr()
|
||||
}
|
||||
|
||||
// Call executes procedure p with arguments a. It will panic, if more then 15 arguments
|
||||
// are supplied.
|
||||
//
|
||||
// The returned error is always non-nil, constructed from the result of GetLastError.
|
||||
// Callers must inspect the primary return value to decide whether an error occurred
|
||||
// (according to the semantics of the specific function being called) before consulting
|
||||
// the error. The error will be guaranteed to contain windows.Errno.
|
||||
func (p *LazyProc) Call(a ...uintptr) (r1, r2 uintptr, lastErr error) {
|
||||
p.mustFind()
|
||||
return p.proc.Call(a...)
|
||||
}
|
14
vendor/src/golang.org/x/sys/windows/env_unset.go
vendored
Normal file
14
vendor/src/golang.org/x/sys/windows/env_unset.go
vendored
Normal file
|
@ -0,0 +1,14 @@
|
|||
// 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 go1.4
|
||||
|
||||
package windows
|
||||
|
||||
import "syscall"
|
||||
|
||||
func Unsetenv(key string) error {
|
||||
// This was added in Go 1.4.
|
||||
return syscall.Unsetenv(key)
|
||||
}
|
25
vendor/src/golang.org/x/sys/windows/env_windows.go
vendored
Normal file
25
vendor/src/golang.org/x/sys/windows/env_windows.go
vendored
Normal file
|
@ -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()
|
||||
}
|
20
vendor/src/golang.org/x/sys/windows/eventlog.go
vendored
Normal file
20
vendor/src/golang.org/x/sys/windows/eventlog.go
vendored
Normal file
|
@ -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
|
97
vendor/src/golang.org/x/sys/windows/exec_windows.go
vendored
Normal file
97
vendor/src/golang.org/x/sys/windows/exec_windows.go
vendored
Normal file
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
30
vendor/src/golang.org/x/sys/windows/race.go
vendored
Normal file
30
vendor/src/golang.org/x/sys/windows/race.go
vendored
Normal file
|
@ -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)
|
||||
}
|
25
vendor/src/golang.org/x/sys/windows/race0.go
vendored
Normal file
25
vendor/src/golang.org/x/sys/windows/race0.go
vendored
Normal file
|
@ -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) {
|
||||
}
|
178
vendor/src/golang.org/x/sys/windows/registry/key.go
vendored
Normal file
178
vendor/src/golang.org/x/sys/windows/registry/key.go
vendored
Normal file
|
@ -0,0 +1,178 @@
|
|||
// 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)
|
||||
)
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
33
vendor/src/golang.org/x/sys/windows/registry/syscall.go
vendored
Normal file
33
vendor/src/golang.org/x/sys/windows/registry/syscall.go
vendored
Normal file
|
@ -0,0 +1,33 @@
|
|||
// 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"
|
||||
|
||||
//go:generate go run $GOROOT/src/syscall/mksyscall_windows.go -output zsyscall_windows.go syscall.go
|
||||
|
||||
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 expandEnvironmentStrings(src *uint16, dst *uint16, size uint32) (n uint32, err error) = kernel32.ExpandEnvironmentStringsW
|
384
vendor/src/golang.org/x/sys/windows/registry/value.go
vendored
Normal file
384
vendor/src/golang.org/x/sys/windows/registry/value.go
vendored
Normal file
|
@ -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
|
||||
}
|
82
vendor/src/golang.org/x/sys/windows/registry/zsyscall_windows.go
vendored
Normal file
82
vendor/src/golang.org/x/sys/windows/registry/zsyscall_windows.go
vendored
Normal file
|
@ -0,0 +1,82 @@
|
|||
// MACHINE GENERATED BY 'go generate' COMMAND; DO NOT EDIT
|
||||
|
||||
package registry
|
||||
|
||||
import "unsafe"
|
||||
import "syscall"
|
||||
|
||||
var _ unsafe.Pointer
|
||||
|
||||
var (
|
||||
modadvapi32 = syscall.NewLazyDLL("advapi32.dll")
|
||||
modkernel32 = syscall.NewLazyDLL("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")
|
||||
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 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 = error(e1)
|
||||
} else {
|
||||
err = syscall.EINVAL
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
435
vendor/src/golang.org/x/sys/windows/security_windows.go
vendored
Normal file
435
vendor/src/golang.org/x/sys/windows/security_windows.go
vendored
Normal file
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
143
vendor/src/golang.org/x/sys/windows/service.go
vendored
Normal file
143
vendor/src/golang.org/x/sys/windows/service.go
vendored
Normal file
|
@ -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
|
22
vendor/src/golang.org/x/sys/windows/str.go
vendored
Normal file
22
vendor/src/golang.org/x/sys/windows/str.go
vendored
Normal file
|
@ -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:])
|
||||
}
|
56
vendor/src/golang.org/x/sys/windows/svc/debug/log.go
vendored
Normal file
56
vendor/src/golang.org/x/sys/windows/svc/debug/log.go
vendored
Normal file
|
@ -0,0 +1,56 @@
|
|||
// 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 debug
|
||||
|
||||
import (
|
||||
"os"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
// Log interface allows different log implementations to be used.
|
||||
type Log interface {
|
||||
Close() error
|
||||
Info(eid uint32, msg string) error
|
||||
Warning(eid uint32, msg string) error
|
||||
Error(eid uint32, msg string) error
|
||||
}
|
||||
|
||||
// ConsoleLog provides access to the console.
|
||||
type ConsoleLog struct {
|
||||
Name string
|
||||
}
|
||||
|
||||
// New creates new ConsoleLog.
|
||||
func New(source string) *ConsoleLog {
|
||||
return &ConsoleLog{Name: source}
|
||||
}
|
||||
|
||||
// Close closes console log l.
|
||||
func (l *ConsoleLog) Close() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (l *ConsoleLog) report(kind string, eid uint32, msg string) error {
|
||||
s := l.Name + "." + kind + "(" + strconv.Itoa(int(eid)) + "): " + msg + "\n"
|
||||
_, err := os.Stdout.Write([]byte(s))
|
||||
return err
|
||||
}
|
||||
|
||||
// Info writes an information event msg with event id eid to the console l.
|
||||
func (l *ConsoleLog) Info(eid uint32, msg string) error {
|
||||
return l.report("info", eid, msg)
|
||||
}
|
||||
|
||||
// Warning writes an warning event msg with event id eid to the console l.
|
||||
func (l *ConsoleLog) Warning(eid uint32, msg string) error {
|
||||
return l.report("warn", eid, msg)
|
||||
}
|
||||
|
||||
// Error writes an error event msg with event id eid to the console l.
|
||||
func (l *ConsoleLog) Error(eid uint32, msg string) error {
|
||||
return l.report("error", eid, msg)
|
||||
}
|
45
vendor/src/golang.org/x/sys/windows/svc/debug/service.go
vendored
Normal file
45
vendor/src/golang.org/x/sys/windows/svc/debug/service.go
vendored
Normal file
|
@ -0,0 +1,45 @@
|
|||
// 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 debug provides facilities to execute svc.Handler on console.
|
||||
//
|
||||
package debug
|
||||
|
||||
import (
|
||||
"os"
|
||||
"os/signal"
|
||||
"syscall"
|
||||
|
||||
"golang.org/x/sys/windows/svc"
|
||||
)
|
||||
|
||||
// Run executes service name by calling appropriate handler function.
|
||||
// The process is running on console, unlike real service. Use Ctrl+C to
|
||||
// send "Stop" command to your service.
|
||||
func Run(name string, handler svc.Handler) error {
|
||||
cmds := make(chan svc.ChangeRequest)
|
||||
changes := make(chan svc.Status)
|
||||
|
||||
sig := make(chan os.Signal)
|
||||
signal.Notify(sig)
|
||||
|
||||
go func() {
|
||||
status := svc.Status{State: svc.Stopped}
|
||||
for {
|
||||
select {
|
||||
case <-sig:
|
||||
cmds <- svc.ChangeRequest{svc.Stop, status}
|
||||
case status = <-changes:
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
_, errno := handler.Execute([]string{name}, cmds, changes)
|
||||
if errno != 0 {
|
||||
return syscall.Errno(errno)
|
||||
}
|
||||
return nil
|
||||
}
|
48
vendor/src/golang.org/x/sys/windows/svc/event.go
vendored
Normal file
48
vendor/src/golang.org/x/sys/windows/svc/event.go
vendored
Normal file
|
@ -0,0 +1,48 @@
|
|||
// 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 svc
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"golang.org/x/sys/windows"
|
||||
)
|
||||
|
||||
// event represents auto-reset, initially non-signaled Windows event.
|
||||
// It is used to communicate between go and asm parts of this package.
|
||||
type event struct {
|
||||
h windows.Handle
|
||||
}
|
||||
|
||||
func newEvent() (*event, error) {
|
||||
h, err := windows.CreateEvent(nil, 0, 0, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &event{h: h}, nil
|
||||
}
|
||||
|
||||
func (e *event) Close() error {
|
||||
return windows.CloseHandle(e.h)
|
||||
}
|
||||
|
||||
func (e *event) Set() error {
|
||||
return windows.SetEvent(e.h)
|
||||
}
|
||||
|
||||
func (e *event) Wait() error {
|
||||
s, err := windows.WaitForSingleObject(e.h, windows.INFINITE)
|
||||
switch s {
|
||||
case windows.WAIT_OBJECT_0:
|
||||
break
|
||||
case windows.WAIT_FAILED:
|
||||
return err
|
||||
default:
|
||||
return errors.New("unexpected result from WaitForSingleObject")
|
||||
}
|
||||
return nil
|
||||
}
|
80
vendor/src/golang.org/x/sys/windows/svc/eventlog/install.go
vendored
Normal file
80
vendor/src/golang.org/x/sys/windows/svc/eventlog/install.go
vendored
Normal file
|
@ -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)
|
||||
}
|
70
vendor/src/golang.org/x/sys/windows/svc/eventlog/log.go
vendored
Normal file
70
vendor/src/golang.org/x/sys/windows/svc/eventlog/log.go
vendored
Normal file
|
@ -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)
|
||||
}
|
24
vendor/src/golang.org/x/sys/windows/svc/go12.c
vendored
Normal file
24
vendor/src/golang.org/x/sys/windows/svc/go12.c
vendored
Normal file
|
@ -0,0 +1,24 @@
|
|||
// 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
|
||||
// +build !go1.3
|
||||
|
||||
// copied from pkg/runtime
|
||||
typedef unsigned int uint32;
|
||||
typedef unsigned long long int uint64;
|
||||
#ifdef _64BIT
|
||||
typedef uint64 uintptr;
|
||||
#else
|
||||
typedef uint32 uintptr;
|
||||
#endif
|
||||
|
||||
// from sys_386.s or sys_amd64.s
|
||||
void ·servicemain(void);
|
||||
|
||||
void
|
||||
·getServiceMain(uintptr *r)
|
||||
{
|
||||
*r = (uintptr)·servicemain;
|
||||
}
|
11
vendor/src/golang.org/x/sys/windows/svc/go12.go
vendored
Normal file
11
vendor/src/golang.org/x/sys/windows/svc/go12.go
vendored
Normal file
|
@ -0,0 +1,11 @@
|
|||
// 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.3
|
||||
|
||||
package svc
|
||||
|
||||
// from go12.c
|
||||
func getServiceMain(r *uintptr)
|
31
vendor/src/golang.org/x/sys/windows/svc/go13.go
vendored
Normal file
31
vendor/src/golang.org/x/sys/windows/svc/go13.go
vendored
Normal file
|
@ -0,0 +1,31 @@
|
|||
// 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.3
|
||||
|
||||
package svc
|
||||
|
||||
import "unsafe"
|
||||
|
||||
const ptrSize = 4 << (^uintptr(0) >> 63) // unsafe.Sizeof(uintptr(0)) but an ideal const
|
||||
|
||||
// Should be a built-in for unsafe.Pointer?
|
||||
func add(p unsafe.Pointer, x uintptr) unsafe.Pointer {
|
||||
return unsafe.Pointer(uintptr(p) + x)
|
||||
}
|
||||
|
||||
// funcPC returns the entry PC of the function f.
|
||||
// It assumes that f is a func value. Otherwise the behavior is undefined.
|
||||
func funcPC(f interface{}) uintptr {
|
||||
return **(**uintptr)(add(unsafe.Pointer(&f), ptrSize))
|
||||
}
|
||||
|
||||
// from sys_386.s and sys_amd64.s
|
||||
func servicectlhandler(ctl uint32) uintptr
|
||||
func servicemain(argc uint32, argv **uint16)
|
||||
|
||||
func getServiceMain(r *uintptr) {
|
||||
*r = funcPC(servicemain)
|
||||
}
|
139
vendor/src/golang.org/x/sys/windows/svc/mgr/config.go
vendored
Normal file
139
vendor/src/golang.org/x/sys/windows/svc/mgr/config.go
vendored
Normal file
|
@ -0,0 +1,139 @@
|
|||
// 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 mgr
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
"unicode/utf16"
|
||||
"unsafe"
|
||||
|
||||
"golang.org/x/sys/windows"
|
||||
)
|
||||
|
||||
const (
|
||||
// Service start types.
|
||||
StartManual = windows.SERVICE_DEMAND_START // the service must be started manually
|
||||
StartAutomatic = windows.SERVICE_AUTO_START // the service will start by itself whenever the computer reboots
|
||||
StartDisabled = windows.SERVICE_DISABLED // the service cannot be started
|
||||
|
||||
// The severity of the error, and action taken,
|
||||
// if this service fails to start.
|
||||
ErrorCritical = windows.SERVICE_ERROR_CRITICAL
|
||||
ErrorIgnore = windows.SERVICE_ERROR_IGNORE
|
||||
ErrorNormal = windows.SERVICE_ERROR_NORMAL
|
||||
ErrorSevere = windows.SERVICE_ERROR_SEVERE
|
||||
)
|
||||
|
||||
// TODO(brainman): Password is not returned by windows.QueryServiceConfig, not sure how to get it.
|
||||
|
||||
type Config struct {
|
||||
ServiceType uint32
|
||||
StartType uint32
|
||||
ErrorControl uint32
|
||||
BinaryPathName string // fully qualified path to the service binary file, can also include arguments for an auto-start service
|
||||
LoadOrderGroup string
|
||||
TagId uint32
|
||||
Dependencies []string
|
||||
ServiceStartName string // name of the account under which the service should run
|
||||
DisplayName string
|
||||
Password string
|
||||
Description string
|
||||
}
|
||||
|
||||
func toString(p *uint16) string {
|
||||
if p == nil {
|
||||
return ""
|
||||
}
|
||||
return syscall.UTF16ToString((*[4096]uint16)(unsafe.Pointer(p))[:])
|
||||
}
|
||||
|
||||
func toStringSlice(ps *uint16) []string {
|
||||
if ps == nil {
|
||||
return nil
|
||||
}
|
||||
r := make([]string, 0)
|
||||
for from, i, p := 0, 0, (*[1 << 24]uint16)(unsafe.Pointer(ps)); true; i++ {
|
||||
if p[i] == 0 {
|
||||
// empty string marks the end
|
||||
if i <= from {
|
||||
break
|
||||
}
|
||||
r = append(r, string(utf16.Decode(p[from:i])))
|
||||
from = i + 1
|
||||
}
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
// Config retrieves service s configuration paramteres.
|
||||
func (s *Service) Config() (Config, error) {
|
||||
var p *windows.QUERY_SERVICE_CONFIG
|
||||
n := uint32(1024)
|
||||
for {
|
||||
b := make([]byte, n)
|
||||
p = (*windows.QUERY_SERVICE_CONFIG)(unsafe.Pointer(&b[0]))
|
||||
err := windows.QueryServiceConfig(s.Handle, p, n, &n)
|
||||
if err == nil {
|
||||
break
|
||||
}
|
||||
if err.(syscall.Errno) != syscall.ERROR_INSUFFICIENT_BUFFER {
|
||||
return Config{}, err
|
||||
}
|
||||
if n <= uint32(len(b)) {
|
||||
return Config{}, err
|
||||
}
|
||||
}
|
||||
|
||||
var p2 *windows.SERVICE_DESCRIPTION
|
||||
n = uint32(1024)
|
||||
for {
|
||||
b := make([]byte, n)
|
||||
p2 = (*windows.SERVICE_DESCRIPTION)(unsafe.Pointer(&b[0]))
|
||||
err := windows.QueryServiceConfig2(s.Handle,
|
||||
windows.SERVICE_CONFIG_DESCRIPTION, &b[0], n, &n)
|
||||
if err == nil {
|
||||
break
|
||||
}
|
||||
if err.(syscall.Errno) != syscall.ERROR_INSUFFICIENT_BUFFER {
|
||||
return Config{}, err
|
||||
}
|
||||
if n <= uint32(len(b)) {
|
||||
return Config{}, err
|
||||
}
|
||||
}
|
||||
|
||||
return Config{
|
||||
ServiceType: p.ServiceType,
|
||||
StartType: p.StartType,
|
||||
ErrorControl: p.ErrorControl,
|
||||
BinaryPathName: toString(p.BinaryPathName),
|
||||
LoadOrderGroup: toString(p.LoadOrderGroup),
|
||||
TagId: p.TagId,
|
||||
Dependencies: toStringSlice(p.Dependencies),
|
||||
ServiceStartName: toString(p.ServiceStartName),
|
||||
DisplayName: toString(p.DisplayName),
|
||||
Description: toString(p2.Description),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func updateDescription(handle windows.Handle, desc string) error {
|
||||
d := windows.SERVICE_DESCRIPTION{toPtr(desc)}
|
||||
return windows.ChangeServiceConfig2(handle,
|
||||
windows.SERVICE_CONFIG_DESCRIPTION, (*byte)(unsafe.Pointer(&d)))
|
||||
}
|
||||
|
||||
// UpdateConfig updates service s configuration parameters.
|
||||
func (s *Service) UpdateConfig(c Config) error {
|
||||
err := windows.ChangeServiceConfig(s.Handle, c.ServiceType, c.StartType,
|
||||
c.ErrorControl, toPtr(c.BinaryPathName), toPtr(c.LoadOrderGroup),
|
||||
nil, toStringBlock(c.Dependencies), toPtr(c.ServiceStartName),
|
||||
toPtr(c.Password), toPtr(c.DisplayName))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return updateDescription(s.Handle, c.Description)
|
||||
}
|
119
vendor/src/golang.org/x/sys/windows/svc/mgr/mgr.go
vendored
Normal file
119
vendor/src/golang.org/x/sys/windows/svc/mgr/mgr.go
vendored
Normal file
|
@ -0,0 +1,119 @@
|
|||
// 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 mgr can be used to manage Windows service programs.
|
||||
// It can be used to install and remove them. It can also start,
|
||||
// stop and pause them. The package can query / change current
|
||||
// service state and config parameters.
|
||||
//
|
||||
package mgr
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
"unicode/utf16"
|
||||
|
||||
"golang.org/x/sys/windows"
|
||||
)
|
||||
|
||||
// Mgr is used to manage Windows service.
|
||||
type Mgr struct {
|
||||
Handle windows.Handle
|
||||
}
|
||||
|
||||
// Connect establishes a connection to the service control manager.
|
||||
func Connect() (*Mgr, error) {
|
||||
return ConnectRemote("")
|
||||
}
|
||||
|
||||
// ConnectRemote establishes a connection to the
|
||||
// service control manager on computer named host.
|
||||
func ConnectRemote(host string) (*Mgr, error) {
|
||||
var s *uint16
|
||||
if host != "" {
|
||||
s = syscall.StringToUTF16Ptr(host)
|
||||
}
|
||||
h, err := windows.OpenSCManager(s, nil, windows.SC_MANAGER_ALL_ACCESS)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &Mgr{Handle: h}, nil
|
||||
}
|
||||
|
||||
// Disconnect closes connection to the service control manager m.
|
||||
func (m *Mgr) Disconnect() error {
|
||||
return windows.CloseServiceHandle(m.Handle)
|
||||
}
|
||||
|
||||
func toPtr(s string) *uint16 {
|
||||
if len(s) == 0 {
|
||||
return nil
|
||||
}
|
||||
return syscall.StringToUTF16Ptr(s)
|
||||
}
|
||||
|
||||
// toStringBlock terminates strings in ss with 0, and then
|
||||
// concatenates them together. It also adds extra 0 at the end.
|
||||
func toStringBlock(ss []string) *uint16 {
|
||||
if len(ss) == 0 {
|
||||
return nil
|
||||
}
|
||||
t := ""
|
||||
for _, s := range ss {
|
||||
if s != "" {
|
||||
t += s + "\x00"
|
||||
}
|
||||
}
|
||||
if t == "" {
|
||||
return nil
|
||||
}
|
||||
t += "\x00"
|
||||
return &utf16.Encode([]rune(t))[0]
|
||||
}
|
||||
|
||||
// CreateService installs new service name on the system.
|
||||
// The service will be executed by running exepath binary.
|
||||
// Use config c to specify service parameters.
|
||||
// If service StartType is set to StartAutomatic,
|
||||
// args will be passed to svc.Handle.Execute.
|
||||
func (m *Mgr) CreateService(name, exepath string, c Config, args ...string) (*Service, error) {
|
||||
if c.StartType == 0 {
|
||||
c.StartType = StartManual
|
||||
}
|
||||
if c.ErrorControl == 0 {
|
||||
c.ErrorControl = ErrorNormal
|
||||
}
|
||||
if c.ServiceType == 0 {
|
||||
c.ServiceType = windows.SERVICE_WIN32_OWN_PROCESS
|
||||
}
|
||||
s := syscall.EscapeArg(exepath)
|
||||
for _, v := range args {
|
||||
s += " " + syscall.EscapeArg(v)
|
||||
}
|
||||
h, err := windows.CreateService(m.Handle, toPtr(name), toPtr(c.DisplayName),
|
||||
windows.SERVICE_ALL_ACCESS, c.ServiceType,
|
||||
c.StartType, c.ErrorControl, toPtr(s), toPtr(c.LoadOrderGroup),
|
||||
nil, toStringBlock(c.Dependencies), toPtr(c.ServiceStartName), toPtr(c.Password))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if c.Description != "" {
|
||||
err = updateDescription(h, c.Description)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return &Service{Name: name, Handle: h}, nil
|
||||
}
|
||||
|
||||
// OpenService retrieves access to service name, so it can
|
||||
// be interrogated and controlled.
|
||||
func (m *Mgr) OpenService(name string) (*Service, error) {
|
||||
h, err := windows.OpenService(m.Handle, syscall.StringToUTF16Ptr(name), windows.SERVICE_ALL_ACCESS)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &Service{Name: name, Handle: h}, nil
|
||||
}
|
74
vendor/src/golang.org/x/sys/windows/svc/mgr/service.go
vendored
Normal file
74
vendor/src/golang.org/x/sys/windows/svc/mgr/service.go
vendored
Normal file
|
@ -0,0 +1,74 @@
|
|||
// 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 mgr
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
|
||||
"golang.org/x/sys/windows"
|
||||
"golang.org/x/sys/windows/svc"
|
||||
)
|
||||
|
||||
// TODO(brainman): Use EnumDependentServices to enumerate dependent services.
|
||||
|
||||
// TODO(brainman): Use EnumServicesStatus to enumerate services in the specified service control manager database.
|
||||
|
||||
// Service is used to access Windows service.
|
||||
type Service struct {
|
||||
Name string
|
||||
Handle windows.Handle
|
||||
}
|
||||
|
||||
// Delete marks service s for deletion from the service control manager database.
|
||||
func (s *Service) Delete() error {
|
||||
return windows.DeleteService(s.Handle)
|
||||
}
|
||||
|
||||
// Close relinquish access to the service s.
|
||||
func (s *Service) Close() error {
|
||||
return windows.CloseServiceHandle(s.Handle)
|
||||
}
|
||||
|
||||
// Start starts service s.
|
||||
// args will be passed to svc.Handler.Execute.
|
||||
func (s *Service) Start(args ...string) error {
|
||||
var p **uint16
|
||||
if len(args) > 0 {
|
||||
vs := make([]*uint16, len(args))
|
||||
for i, _ := range vs {
|
||||
vs[i] = syscall.StringToUTF16Ptr(args[i])
|
||||
}
|
||||
p = &vs[0]
|
||||
}
|
||||
return windows.StartService(s.Handle, uint32(len(args)), p)
|
||||
}
|
||||
|
||||
// Control sends state change request c to the servce s.
|
||||
func (s *Service) Control(c svc.Cmd) (svc.Status, error) {
|
||||
var t windows.SERVICE_STATUS
|
||||
err := windows.ControlService(s.Handle, uint32(c), &t)
|
||||
if err != nil {
|
||||
return svc.Status{}, err
|
||||
}
|
||||
return svc.Status{
|
||||
State: svc.State(t.CurrentState),
|
||||
Accepts: svc.Accepted(t.ControlsAccepted),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Query returns current status of service s.
|
||||
func (s *Service) Query() (svc.Status, error) {
|
||||
var t windows.SERVICE_STATUS
|
||||
err := windows.QueryServiceStatus(s.Handle, &t)
|
||||
if err != nil {
|
||||
return svc.Status{}, err
|
||||
}
|
||||
return svc.Status{
|
||||
State: svc.State(t.CurrentState),
|
||||
Accepts: svc.Accepted(t.ControlsAccepted),
|
||||
}, nil
|
||||
}
|
62
vendor/src/golang.org/x/sys/windows/svc/security.go
vendored
Normal file
62
vendor/src/golang.org/x/sys/windows/svc/security.go
vendored
Normal file
|
@ -0,0 +1,62 @@
|
|||
// 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 svc
|
||||
|
||||
import (
|
||||
"unsafe"
|
||||
|
||||
"golang.org/x/sys/windows"
|
||||
)
|
||||
|
||||
func allocSid(subAuth0 uint32) (*windows.SID, error) {
|
||||
var sid *windows.SID
|
||||
err := windows.AllocateAndInitializeSid(&windows.SECURITY_NT_AUTHORITY,
|
||||
1, subAuth0, 0, 0, 0, 0, 0, 0, 0, &sid)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return sid, nil
|
||||
}
|
||||
|
||||
// IsAnInteractiveSession determines if calling process is running interactively.
|
||||
// It queries the process token for membership in the Interactive group.
|
||||
// http://stackoverflow.com/questions/2668851/how-do-i-detect-that-my-application-is-running-as-service-or-in-an-interactive-s
|
||||
func IsAnInteractiveSession() (bool, error) {
|
||||
interSid, err := allocSid(windows.SECURITY_INTERACTIVE_RID)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
defer windows.FreeSid(interSid)
|
||||
|
||||
serviceSid, err := allocSid(windows.SECURITY_SERVICE_RID)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
defer windows.FreeSid(serviceSid)
|
||||
|
||||
t, err := windows.OpenCurrentProcessToken()
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
defer t.Close()
|
||||
|
||||
gs, err := t.GetTokenGroups()
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
p := unsafe.Pointer(&gs.Groups[0])
|
||||
groups := (*[2 << 20]windows.SIDAndAttributes)(p)[:gs.GroupCount]
|
||||
for _, g := range groups {
|
||||
if windows.EqualSid(g.Sid, interSid) {
|
||||
return true, nil
|
||||
}
|
||||
if windows.EqualSid(g.Sid, serviceSid) {
|
||||
return false, nil
|
||||
}
|
||||
}
|
||||
return false, nil
|
||||
}
|
316
vendor/src/golang.org/x/sys/windows/svc/service.go
vendored
Normal file
316
vendor/src/golang.org/x/sys/windows/svc/service.go
vendored
Normal file
|
@ -0,0 +1,316 @@
|
|||
// 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 svc provides everything required to build Windows service.
|
||||
//
|
||||
package svc
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"runtime"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
|
||||
"golang.org/x/sys/windows"
|
||||
)
|
||||
|
||||
// State describes service execution state (Stopped, Running and so on).
|
||||
type State uint32
|
||||
|
||||
const (
|
||||
Stopped = State(windows.SERVICE_STOPPED)
|
||||
StartPending = State(windows.SERVICE_START_PENDING)
|
||||
StopPending = State(windows.SERVICE_STOP_PENDING)
|
||||
Running = State(windows.SERVICE_RUNNING)
|
||||
ContinuePending = State(windows.SERVICE_CONTINUE_PENDING)
|
||||
PausePending = State(windows.SERVICE_PAUSE_PENDING)
|
||||
Paused = State(windows.SERVICE_PAUSED)
|
||||
)
|
||||
|
||||
// Cmd represents service state change request. It is sent to a service
|
||||
// by the service manager, and should be actioned upon by the service.
|
||||
type Cmd uint32
|
||||
|
||||
const (
|
||||
Stop = Cmd(windows.SERVICE_CONTROL_STOP)
|
||||
Pause = Cmd(windows.SERVICE_CONTROL_PAUSE)
|
||||
Continue = Cmd(windows.SERVICE_CONTROL_CONTINUE)
|
||||
Interrogate = Cmd(windows.SERVICE_CONTROL_INTERROGATE)
|
||||
Shutdown = Cmd(windows.SERVICE_CONTROL_SHUTDOWN)
|
||||
)
|
||||
|
||||
// Accepted is used to describe commands accepted by the service.
|
||||
// Note that Interrogate is always accepted.
|
||||
type Accepted uint32
|
||||
|
||||
const (
|
||||
AcceptStop = Accepted(windows.SERVICE_ACCEPT_STOP)
|
||||
AcceptShutdown = Accepted(windows.SERVICE_ACCEPT_SHUTDOWN)
|
||||
AcceptPauseAndContinue = Accepted(windows.SERVICE_ACCEPT_PAUSE_CONTINUE)
|
||||
)
|
||||
|
||||
// Status combines State and Accepted commands to fully describe running service.
|
||||
type Status struct {
|
||||
State State
|
||||
Accepts Accepted
|
||||
CheckPoint uint32 // used to report progress during a lengthy operation
|
||||
WaitHint uint32 // estimated time required for a pending operation, in milliseconds
|
||||
}
|
||||
|
||||
// ChangeRequest is sent to the service Handler to request service status change.
|
||||
type ChangeRequest struct {
|
||||
Cmd Cmd
|
||||
CurrentStatus Status
|
||||
}
|
||||
|
||||
// Handler is the interface that must be implemented to build Windows service.
|
||||
type Handler interface {
|
||||
|
||||
// Execute will be called by the package code at the start of
|
||||
// the service, and the service will exit once Execute completes.
|
||||
// Inside Execute you must read service change requests from r and
|
||||
// act accordingly. You must keep service control manager up to date
|
||||
// about state of your service by writing into s as required.
|
||||
// args contains service name followed by argument strings passed
|
||||
// to the service.
|
||||
// You can provide service exit code in exitCode return parameter,
|
||||
// with 0 being "no error". You can also indicate if exit code,
|
||||
// if any, is service specific or not by using svcSpecificEC
|
||||
// parameter.
|
||||
Execute(args []string, r <-chan ChangeRequest, s chan<- Status) (svcSpecificEC bool, exitCode uint32)
|
||||
}
|
||||
|
||||
var (
|
||||
// These are used by asm code.
|
||||
goWaitsH uintptr
|
||||
cWaitsH uintptr
|
||||
ssHandle uintptr
|
||||
sName *uint16
|
||||
sArgc uintptr
|
||||
sArgv **uint16
|
||||
ctlHandlerProc uintptr
|
||||
cSetEvent uintptr
|
||||
cWaitForSingleObject uintptr
|
||||
cRegisterServiceCtrlHandlerW uintptr
|
||||
)
|
||||
|
||||
func init() {
|
||||
k := syscall.MustLoadDLL("kernel32.dll")
|
||||
cSetEvent = k.MustFindProc("SetEvent").Addr()
|
||||
cWaitForSingleObject = k.MustFindProc("WaitForSingleObject").Addr()
|
||||
a := syscall.MustLoadDLL("advapi32.dll")
|
||||
cRegisterServiceCtrlHandlerW = a.MustFindProc("RegisterServiceCtrlHandlerW").Addr()
|
||||
}
|
||||
|
||||
type ctlEvent struct {
|
||||
cmd Cmd
|
||||
errno uint32
|
||||
}
|
||||
|
||||
// service provides access to windows service api.
|
||||
type service struct {
|
||||
name string
|
||||
h windows.Handle
|
||||
cWaits *event
|
||||
goWaits *event
|
||||
c chan ctlEvent
|
||||
handler Handler
|
||||
}
|
||||
|
||||
func newService(name string, handler Handler) (*service, error) {
|
||||
var s service
|
||||
var err error
|
||||
s.name = name
|
||||
s.c = make(chan ctlEvent)
|
||||
s.handler = handler
|
||||
s.cWaits, err = newEvent()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
s.goWaits, err = newEvent()
|
||||
if err != nil {
|
||||
s.cWaits.Close()
|
||||
return nil, err
|
||||
}
|
||||
return &s, nil
|
||||
}
|
||||
|
||||
func (s *service) close() error {
|
||||
s.cWaits.Close()
|
||||
s.goWaits.Close()
|
||||
return nil
|
||||
}
|
||||
|
||||
type exitCode struct {
|
||||
isSvcSpecific bool
|
||||
errno uint32
|
||||
}
|
||||
|
||||
func (s *service) updateStatus(status *Status, ec *exitCode) error {
|
||||
if s.h == 0 {
|
||||
return errors.New("updateStatus with no service status handle")
|
||||
}
|
||||
var t windows.SERVICE_STATUS
|
||||
t.ServiceType = windows.SERVICE_WIN32_OWN_PROCESS
|
||||
t.CurrentState = uint32(status.State)
|
||||
if status.Accepts&AcceptStop != 0 {
|
||||
t.ControlsAccepted |= windows.SERVICE_ACCEPT_STOP
|
||||
}
|
||||
if status.Accepts&AcceptShutdown != 0 {
|
||||
t.ControlsAccepted |= windows.SERVICE_ACCEPT_SHUTDOWN
|
||||
}
|
||||
if status.Accepts&AcceptPauseAndContinue != 0 {
|
||||
t.ControlsAccepted |= windows.SERVICE_ACCEPT_PAUSE_CONTINUE
|
||||
}
|
||||
if ec.errno == 0 {
|
||||
t.Win32ExitCode = windows.NO_ERROR
|
||||
t.ServiceSpecificExitCode = windows.NO_ERROR
|
||||
} else if ec.isSvcSpecific {
|
||||
t.Win32ExitCode = uint32(windows.ERROR_SERVICE_SPECIFIC_ERROR)
|
||||
t.ServiceSpecificExitCode = ec.errno
|
||||
} else {
|
||||
t.Win32ExitCode = ec.errno
|
||||
t.ServiceSpecificExitCode = windows.NO_ERROR
|
||||
}
|
||||
t.CheckPoint = status.CheckPoint
|
||||
t.WaitHint = status.WaitHint
|
||||
return windows.SetServiceStatus(s.h, &t)
|
||||
}
|
||||
|
||||
const (
|
||||
sysErrSetServiceStatusFailed = uint32(syscall.APPLICATION_ERROR) + iota
|
||||
sysErrNewThreadInCallback
|
||||
)
|
||||
|
||||
func (s *service) run() {
|
||||
s.goWaits.Wait()
|
||||
s.h = windows.Handle(ssHandle)
|
||||
argv := (*[100]*int16)(unsafe.Pointer(sArgv))[:sArgc]
|
||||
args := make([]string, len(argv))
|
||||
for i, a := range argv {
|
||||
args[i] = syscall.UTF16ToString((*[1 << 20]uint16)(unsafe.Pointer(a))[:])
|
||||
}
|
||||
|
||||
cmdsToHandler := make(chan ChangeRequest)
|
||||
changesFromHandler := make(chan Status)
|
||||
exitFromHandler := make(chan exitCode)
|
||||
|
||||
go func() {
|
||||
ss, errno := s.handler.Execute(args, cmdsToHandler, changesFromHandler)
|
||||
exitFromHandler <- exitCode{ss, errno}
|
||||
}()
|
||||
|
||||
status := Status{State: Stopped}
|
||||
ec := exitCode{isSvcSpecific: true, errno: 0}
|
||||
var outch chan ChangeRequest
|
||||
inch := s.c
|
||||
var cmd Cmd
|
||||
loop:
|
||||
for {
|
||||
select {
|
||||
case r := <-inch:
|
||||
if r.errno != 0 {
|
||||
ec.errno = r.errno
|
||||
break loop
|
||||
}
|
||||
inch = nil
|
||||
outch = cmdsToHandler
|
||||
cmd = r.cmd
|
||||
case outch <- ChangeRequest{cmd, status}:
|
||||
inch = s.c
|
||||
outch = nil
|
||||
case c := <-changesFromHandler:
|
||||
err := s.updateStatus(&c, &ec)
|
||||
if err != nil {
|
||||
// best suitable error number
|
||||
ec.errno = sysErrSetServiceStatusFailed
|
||||
if err2, ok := err.(syscall.Errno); ok {
|
||||
ec.errno = uint32(err2)
|
||||
}
|
||||
break loop
|
||||
}
|
||||
status = c
|
||||
case ec = <-exitFromHandler:
|
||||
break loop
|
||||
}
|
||||
}
|
||||
|
||||
s.updateStatus(&Status{State: Stopped}, &ec)
|
||||
s.cWaits.Set()
|
||||
}
|
||||
|
||||
func newCallback(fn interface{}) (cb uintptr, err error) {
|
||||
defer func() {
|
||||
r := recover()
|
||||
if r == nil {
|
||||
return
|
||||
}
|
||||
cb = 0
|
||||
switch v := r.(type) {
|
||||
case string:
|
||||
err = errors.New(v)
|
||||
case error:
|
||||
err = v
|
||||
default:
|
||||
err = errors.New("unexpected panic in syscall.NewCallback")
|
||||
}
|
||||
}()
|
||||
return syscall.NewCallback(fn), nil
|
||||
}
|
||||
|
||||
// BUG(brainman): There is no mechanism to run multiple services
|
||||
// inside one single executable. Perhaps, it can be overcome by
|
||||
// using RegisterServiceCtrlHandlerEx Windows api.
|
||||
|
||||
// Run executes service name by calling appropriate handler function.
|
||||
func Run(name string, handler Handler) error {
|
||||
runtime.LockOSThread()
|
||||
|
||||
tid := windows.GetCurrentThreadId()
|
||||
|
||||
s, err := newService(name, handler)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ctlHandler := func(ctl uint32) uintptr {
|
||||
e := ctlEvent{cmd: Cmd(ctl)}
|
||||
// We assume that this callback function is running on
|
||||
// the same thread as Run. Nowhere in MS documentation
|
||||
// I could find statement to guarantee that. So putting
|
||||
// check here to verify, otherwise things will go bad
|
||||
// quickly, if ignored.
|
||||
i := windows.GetCurrentThreadId()
|
||||
if i != tid {
|
||||
e.errno = sysErrNewThreadInCallback
|
||||
}
|
||||
s.c <- e
|
||||
return 0
|
||||
}
|
||||
|
||||
var svcmain uintptr
|
||||
getServiceMain(&svcmain)
|
||||
t := []windows.SERVICE_TABLE_ENTRY{
|
||||
{syscall.StringToUTF16Ptr(s.name), svcmain},
|
||||
{nil, 0},
|
||||
}
|
||||
|
||||
goWaitsH = uintptr(s.goWaits.h)
|
||||
cWaitsH = uintptr(s.cWaits.h)
|
||||
sName = t[0].ServiceName
|
||||
ctlHandlerProc, err = newCallback(ctlHandler)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
go s.run()
|
||||
|
||||
err = windows.StartServiceCtrlDispatcher(&t[0])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
67
vendor/src/golang.org/x/sys/windows/svc/sys_386.s
vendored
Normal file
67
vendor/src/golang.org/x/sys/windows/svc/sys_386.s
vendored
Normal file
|
@ -0,0 +1,67 @@
|
|||
// 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
|
||||
|
||||
// func servicemain(argc uint32, argv **uint16)
|
||||
TEXT ·servicemain(SB),7,$0
|
||||
MOVL argc+0(FP), AX
|
||||
MOVL AX, ·sArgc(SB)
|
||||
MOVL argv+4(FP), AX
|
||||
MOVL AX, ·sArgv(SB)
|
||||
|
||||
PUSHL BP
|
||||
PUSHL BX
|
||||
PUSHL SI
|
||||
PUSHL DI
|
||||
|
||||
SUBL $12, SP
|
||||
|
||||
MOVL ·sName(SB), AX
|
||||
MOVL AX, (SP)
|
||||
MOVL $·servicectlhandler(SB), AX
|
||||
MOVL AX, 4(SP)
|
||||
MOVL ·cRegisterServiceCtrlHandlerW(SB), AX
|
||||
MOVL SP, BP
|
||||
CALL AX
|
||||
MOVL BP, SP
|
||||
CMPL AX, $0
|
||||
JE exit
|
||||
MOVL AX, ·ssHandle(SB)
|
||||
|
||||
MOVL ·goWaitsH(SB), AX
|
||||
MOVL AX, (SP)
|
||||
MOVL ·cSetEvent(SB), AX
|
||||
MOVL SP, BP
|
||||
CALL AX
|
||||
MOVL BP, SP
|
||||
|
||||
MOVL ·cWaitsH(SB), AX
|
||||
MOVL AX, (SP)
|
||||
MOVL $-1, AX
|
||||
MOVL AX, 4(SP)
|
||||
MOVL ·cWaitForSingleObject(SB), AX
|
||||
MOVL SP, BP
|
||||
CALL AX
|
||||
MOVL BP, SP
|
||||
|
||||
exit:
|
||||
ADDL $12, SP
|
||||
|
||||
POPL DI
|
||||
POPL SI
|
||||
POPL BX
|
||||
POPL BP
|
||||
|
||||
MOVL 0(SP), CX
|
||||
ADDL $12, SP
|
||||
JMP CX
|
||||
|
||||
// I do not know why, but this seems to be the only way to call
|
||||
// ctlHandlerProc on Windows 7.
|
||||
|
||||
// func servicectlhandler(ctl uint32) uintptr
|
||||
TEXT ·servicectlhandler(SB),7,$0
|
||||
MOVL ·ctlHandlerProc(SB), CX
|
||||
JMP CX
|
41
vendor/src/golang.org/x/sys/windows/svc/sys_amd64.s
vendored
Normal file
41
vendor/src/golang.org/x/sys/windows/svc/sys_amd64.s
vendored
Normal file
|
@ -0,0 +1,41 @@
|
|||
// 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
|
||||
|
||||
// func servicemain(argc uint32, argv **uint16)
|
||||
TEXT ·servicemain(SB),7,$0
|
||||
MOVL CX, ·sArgc(SB)
|
||||
MOVL DX, ·sArgv(SB)
|
||||
|
||||
SUBQ $32, SP // stack for the first 4 syscall params
|
||||
|
||||
MOVQ ·sName(SB), CX
|
||||
MOVQ $·servicectlhandler(SB), DX
|
||||
MOVQ ·cRegisterServiceCtrlHandlerW(SB), AX
|
||||
CALL AX
|
||||
CMPQ AX, $0
|
||||
JE exit
|
||||
MOVQ AX, ·ssHandle(SB)
|
||||
|
||||
MOVQ ·goWaitsH(SB), CX
|
||||
MOVQ ·cSetEvent(SB), AX
|
||||
CALL AX
|
||||
|
||||
MOVQ ·cWaitsH(SB), CX
|
||||
MOVQ $4294967295, DX
|
||||
MOVQ ·cWaitForSingleObject(SB), AX
|
||||
CALL AX
|
||||
|
||||
exit:
|
||||
ADDQ $32, SP
|
||||
RET
|
||||
|
||||
// I do not know why, but this seems to be the only way to call
|
||||
// ctlHandlerProc on Windows 7.
|
||||
|
||||
// func servicectlhandler(ctl uint32) uintptr
|
||||
TEXT ·servicectlhandler(SB),7,$0
|
||||
MOVQ ·ctlHandlerProc(SB), AX
|
||||
JMP AX
|
77
vendor/src/golang.org/x/sys/windows/syscall.go
vendored
Normal file
77
vendor/src/golang.org/x/sys/windows/syscall.go
vendored
Normal file
|
@ -0,0 +1,77 @@
|
|||
// 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"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
// use is a no-op, but the compiler cannot see that it is.
|
||||
// Calling use(p) ensures that p is kept live until that point.
|
||||
//go:noescape
|
||||
func use(p unsafe.Pointer)
|
990
vendor/src/golang.org/x/sys/windows/syscall_windows.go
vendored
Normal file
990
vendor/src/golang.org/x/sys/windows/syscall_windows.go
vendored
Normal file
|
@ -0,0 +1,990 @@
|
|||
// 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"
|
||||
)
|
||||
|
||||
//go:generate go run $GOROOT/src/syscall/mksyscall_windows.go -output zsyscall_windows.go eventlog.go service.go syscall_windows.go security_windows.go
|
||||
|
||||
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 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
|
||||
}
|
2220
vendor/src/golang.org/x/sys/windows/zsyscall_windows.go
vendored
Normal file
2220
vendor/src/golang.org/x/sys/windows/zsyscall_windows.go
vendored
Normal file
File diff suppressed because it is too large
Load diff
1242
vendor/src/golang.org/x/sys/windows/ztypes_windows.go
vendored
Normal file
1242
vendor/src/golang.org/x/sys/windows/ztypes_windows.go
vendored
Normal file
File diff suppressed because it is too large
Load diff
22
vendor/src/golang.org/x/sys/windows/ztypes_windows_386.go
vendored
Normal file
22
vendor/src/golang.org/x/sys/windows/ztypes_windows_386.go
vendored
Normal file
|
@ -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
|
||||
}
|
22
vendor/src/golang.org/x/sys/windows/ztypes_windows_amd64.go
vendored
Normal file
22
vendor/src/golang.org/x/sys/windows/ztypes_windows_amd64.go
vendored
Normal file
|
@ -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
|
||||
}
|
Loading…
Add table
Reference in a new issue