]> Cypherpunks repositories - gostls13.git/commitdiff
os: implement env using native windows api.
authorAlex Brainman <alex.brainman@gmail.com>
Fri, 13 Aug 2010 04:29:23 +0000 (14:29 +1000)
committerAlex Brainman <alex.brainman@gmail.com>
Fri, 13 Aug 2010 04:29:23 +0000 (14:29 +1000)
Fixes #864.

R=rsc
CC=golang-dev
https://golang.org/cl/1975043

src/pkg/os/Makefile
src/pkg/os/env.go [deleted file]
src/pkg/os/env_unix.go [changed mode: 0755->0644]
src/pkg/os/env_windows.go [changed mode: 0755->0644]
src/pkg/os/os_test.go
src/pkg/syscall/syscall_windows.go
src/pkg/syscall/zsyscall_windows_386.go
src/pkg/syscall/ztypes_windows_386.go

index 45954bbeb81104e65e8db6478429a1f40cd43870..f1ad9af0705263a98ca87c2a905ab9669eb98a99 100644 (file)
@@ -7,7 +7,6 @@ include ../../Make.$(GOARCH)
 TARG=os
 GOFILES=\
        dir_$(GOOS).go\
-       env.go\
        error.go\
        exec.go\
        file.go\
diff --git a/src/pkg/os/env.go b/src/pkg/os/env.go
deleted file mode 100644 (file)
index 3ce84b5..0000000
+++ /dev/null
@@ -1,87 +0,0 @@
-// 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.
-
-// Environment variables.
-
-package os
-
-import (
-       "sync"
-)
-
-// ENOENV is the Error indicating that an environment variable does not exist.
-var ENOENV = NewError("no such environment variable")
-
-var env map[string]string
-var once sync.Once
-
-
-func copyenv() {
-       env = make(map[string]string)
-       for _, s := range Envs {
-               for j := 0; j < len(s); j++ {
-                       if s[j] == '=' {
-                               env[s[0:j]] = s[j+1:]
-                               break
-                       }
-               }
-       }
-}
-
-// Getenverror retrieves the value of the environment variable named by the key.
-// It returns the value and an error, if any.
-func Getenverror(key string) (value string, err Error) {
-       once.Do(copyenv)
-
-       if len(key) == 0 {
-               return "", EINVAL
-       }
-       v, ok := env[key]
-       if !ok {
-               return "", ENOENV
-       }
-       return v, nil
-}
-
-// Getenv retrieves the value of the environment variable named by the key.
-// It returns the value, which will be empty if the variable is not present.
-func Getenv(key string) string {
-       v, _ := Getenverror(key)
-       return v
-}
-
-// Setenv sets the value of the environment variable named by the key.
-// It returns an Error, if any.
-func Setenv(key, value string) Error {
-       once.Do(copyenv)
-
-       if len(key) == 0 {
-               return EINVAL
-       }
-       env[key] = value
-       return nil
-}
-
-// Clearenv deletes all environment variables.
-func Clearenv() {
-       once.Do(copyenv) // prevent copyenv in Getenv/Setenv
-       env = make(map[string]string)
-}
-
-// Environ returns an array of strings representing the environment,
-// in the form "key=value".
-func Environ() []string {
-       once.Do(copyenv)
-       a := make([]string, len(env))
-       i := 0
-       for k, v := range env {
-               // check i < len(a) for safety,
-               // in case env is changing underfoot.
-               if i < len(a) {
-                       a[i] = k + "=" + v
-                       i++
-               }
-       }
-       return a[0:i]
-}
old mode 100755 (executable)
new mode 100644 (file)
index 0c13bda..e7e1c3b
@@ -6,10 +6,87 @@
 
 package os
 
+import (
+       "sync"
+)
+
+// ENOENV is the Error indicating that an environment variable does not exist.
+var ENOENV = NewError("no such environment variable")
+
+var env map[string]string
+var once sync.Once
+
+
+func copyenv() {
+       env = make(map[string]string)
+       for _, s := range Envs {
+               for j := 0; j < len(s); j++ {
+                       if s[j] == '=' {
+                               env[s[0:j]] = s[j+1:]
+                               break
+                       }
+               }
+       }
+}
+
+// Getenverror retrieves the value of the environment variable named by the key.
+// It returns the value and an error, if any.
+func Getenverror(key string) (value string, err Error) {
+       once.Do(copyenv)
+
+       if len(key) == 0 {
+               return "", EINVAL
+       }
+       v, ok := env[key]
+       if !ok {
+               return "", ENOENV
+       }
+       return v, nil
+}
+
+// Getenv retrieves the value of the environment variable named by the key.
+// It returns the value, which will be empty if the variable is not present.
+func Getenv(key string) string {
+       v, _ := Getenverror(key)
+       return v
+}
+
+// Setenv sets the value of the environment variable named by the key.
+// It returns an Error, if any.
+func Setenv(key, value string) Error {
+       once.Do(copyenv)
+
+       if len(key) == 0 {
+               return EINVAL
+       }
+       env[key] = value
+       return nil
+}
+
+// Clearenv deletes all environment variables.
+func Clearenv() {
+       once.Do(copyenv) // prevent copyenv in Getenv/Setenv
+       env = make(map[string]string)
+}
+
+// Environ returns an array of strings representing the environment,
+// in the form "key=value".
+func Environ() []string {
+       once.Do(copyenv)
+       a := make([]string, len(env))
+       i := 0
+       for k, v := range env {
+               // check i < len(a) for safety,
+               // in case env is changing underfoot.
+               if i < len(a) {
+                       a[i] = k + "=" + v
+                       i++
+               }
+       }
+       return a[0:i]
+}
+
 // TempDir returns the default directory to use for temporary files.
-// On Unix-like systems, it uses the environment variable $TMPDIR
-// or, if that is empty, /tmp.
-// On Windows systems, it uses the Windows GetTempPath API.
 func TempDir() string {
        dir := Getenv("TMPDIR")
        if dir == "" {
old mode 100755 (executable)
new mode 100644 (file)
index 7d5b007..4b224d5
@@ -9,8 +9,99 @@ package os
 import (
        "syscall"
        "utf16"
+       "unsafe"
 )
 
+// ENOENV is the Error indicating that an environment variable does not exist.
+var ENOENV = NewError("no such environment variable")
+
+// Getenverror retrieves the value of the environment variable named by the key.
+// It returns the value and an error, if any.
+func Getenverror(key string) (value string, err Error) {
+       b := make([]uint16, 100)
+       n, e := syscall.GetEnvironmentVariable(syscall.StringToUTF16Ptr(key), &b[0], uint32(len(b)))
+       if n == 0 && e == syscall.ERROR_ENVVAR_NOT_FOUND {
+               return "", ENOENV
+       }
+       if n > uint32(len(b)) {
+               b = make([]uint16, n)
+               n, e = syscall.GetEnvironmentVariable(syscall.StringToUTF16Ptr(key), &b[0], uint32(len(b)))
+               if n > uint32(len(b)) {
+                       n = 0
+               }
+       }
+       if n == 0 {
+               return "", NewSyscallError("GetEnvironmentVariable", e)
+       }
+       return string(utf16.Decode(b[0:n])), nil
+}
+
+// Getenv retrieves the value of the environment variable named by the key.
+// It returns the value, which will be empty if the variable is not present.
+func Getenv(key string) string {
+       v, _ := Getenverror(key)
+       return v
+}
+
+// Setenv sets the value of the environment variable named by the key.
+// It returns an Error, if any.
+func Setenv(key, value string) Error {
+       var v *uint16
+       if len(value) > 0 {
+               v = syscall.StringToUTF16Ptr(value)
+       }
+       ok, e := syscall.SetEnvironmentVariable(syscall.StringToUTF16Ptr(key), v)
+       if !ok {
+               return NewSyscallError("SetEnvironmentVariable", e)
+       }
+       return nil
+}
+
+// Clearenv deletes all environment variables.
+func Clearenv() {
+       for _, s := range Environ() {
+               for j := 0; j < len(s); j++ {
+                       if s[j] == '=' {
+                               Setenv(s[0:j], "")
+                       }
+               }
+       }
+}
+
+// Environ returns an array of strings representing the environment,
+// in the form "key=value".
+func Environ() []string {
+       s, e := syscall.GetEnvironmentStrings()
+       if e != 0 {
+               return nil
+       }
+       defer syscall.FreeEnvironmentStrings(s)
+       r := make([]string, 0, 50) // Empty with room to grow.
+       for from, i, p := 0, 0, (*[1 << 24]uint16)(unsafe.Pointer(s)); true; i++ {
+               if p[i] == 0 {
+                       // empty string marks the end
+                       if i <= from {
+                               break
+                       }
+                       // skip anything that starts with '='
+                       if p[from] != '=' {
+                               if len(r) == cap(r) {
+                                       nr := make([]string, len(r), 2*len(r))
+                                       for k := 0; k < len(r); k++ {
+                                               nr[k] = r[k]
+                                       }
+                                       r = nr
+                               }
+                               r = r[0 : len(r)+1]
+                               r[len(r)-1] = string(utf16.Decode(p[from:i]))
+                       }
+                       from = i + 1
+               }
+       }
+       return r
+}
+
+// TempDir returns the default directory to use for temporary files.
 func TempDir() string {
        const pathSep = '\\'
        dirw := make([]uint16, syscall.MAX_PATH)
index 9b206d0c6f56d2388ac69eb313d2e0f132b6a529..05af090dae0dd24bf338448d109fb84bc5a5cc14 100644 (file)
@@ -18,7 +18,7 @@ import (
 var dot = []string{
        "dir_darwin.go",
        "dir_linux.go",
-       "env.go",
+       "env_unix.go",
        "error.go",
        "file.go",
        "os_test.go",
index 5ab4dd0758d1af6ffe4e53768bff184eebd8e777..ca00e72ac4e4b9cb9d579183b683f296c7981e49 100644 (file)
@@ -143,6 +143,10 @@ func getSysProcAddr(m uint32, pname string) uintptr {
 //sys  CryptAcquireContext(provhandle *uint32, container *uint16, provider *uint16, provtype uint32, flags uint32) (ok bool, errno int) = advapi32.CryptAcquireContextW
 //sys  CryptReleaseContext(provhandle uint32, flags uint32) (ok bool, errno int) = advapi32.CryptReleaseContext
 //sys  CryptGenRandom(provhandle uint32, buflen uint32, buf *byte) (ok bool, errno int) = advapi32.CryptGenRandom
+//sys  GetEnvironmentStrings() (envs *uint16, errno int) [failretval=nil] = kernel32.GetEnvironmentStringsW
+//sys  FreeEnvironmentStrings(envs *uint16) (ok bool, errno int) = kernel32.FreeEnvironmentStringsW
+//sys  GetEnvironmentVariable(name *uint16, buffer *uint16, size uint32) (n uint32, errno int) = kernel32.GetEnvironmentVariableW
+//sys  SetEnvironmentVariable(name *uint16, value *uint16) (ok bool, errno int) = kernel32.SetEnvironmentVariableW
 
 // syscall interface implementation for other packages
 
index 8bc1e4363735e80b6c260b7aaa3f4df637f5e74a..e990fcb4d47c83bd38583be06fdd958f3b9e4a83 100644 (file)
@@ -53,6 +53,10 @@ var (
        procCryptAcquireContextW       = getSysProcAddr(modadvapi32, "CryptAcquireContextW")
        procCryptReleaseContext        = getSysProcAddr(modadvapi32, "CryptReleaseContext")
        procCryptGenRandom             = getSysProcAddr(modadvapi32, "CryptGenRandom")
+       procGetEnvironmentStringsW     = getSysProcAddr(modkernel32, "GetEnvironmentStringsW")
+       procFreeEnvironmentStringsW    = getSysProcAddr(modkernel32, "FreeEnvironmentStringsW")
+       procGetEnvironmentVariableW    = getSysProcAddr(modkernel32, "GetEnvironmentVariableW")
+       procSetEnvironmentVariableW    = getSysProcAddr(modkernel32, "SetEnvironmentVariableW")
        procWSAStartup                 = getSysProcAddr(modwsock32, "WSAStartup")
        procWSACleanup                 = getSysProcAddr(modwsock32, "WSACleanup")
        procsocket                     = getSysProcAddr(modwsock32, "socket")
@@ -674,6 +678,66 @@ func CryptGenRandom(provhandle uint32, buflen uint32, buf *byte) (ok bool, errno
        return
 }
 
+func GetEnvironmentStrings() (envs *uint16, errno int) {
+       r0, _, e1 := Syscall(procGetEnvironmentStringsW, 0, 0, 0)
+       envs = (*uint16)(unsafe.Pointer(r0))
+       if envs == nil {
+               if e1 != 0 {
+                       errno = int(e1)
+               } else {
+                       errno = EINVAL
+               }
+       } else {
+               errno = 0
+       }
+       return
+}
+
+func FreeEnvironmentStrings(envs *uint16) (ok bool, errno int) {
+       r0, _, e1 := Syscall(procFreeEnvironmentStringsW, uintptr(unsafe.Pointer(envs)), 0, 0)
+       ok = bool(r0 != 0)
+       if !ok {
+               if e1 != 0 {
+                       errno = int(e1)
+               } else {
+                       errno = EINVAL
+               }
+       } else {
+               errno = 0
+       }
+       return
+}
+
+func GetEnvironmentVariable(name *uint16, buffer *uint16, size uint32) (n uint32, errno int) {
+       r0, _, e1 := Syscall(procGetEnvironmentVariableW, uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(buffer)), uintptr(size))
+       n = uint32(r0)
+       if n == 0 {
+               if e1 != 0 {
+                       errno = int(e1)
+               } else {
+                       errno = EINVAL
+               }
+       } else {
+               errno = 0
+       }
+       return
+}
+
+func SetEnvironmentVariable(name *uint16, value *uint16) (ok bool, errno int) {
+       r0, _, e1 := Syscall(procSetEnvironmentVariableW, uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(value)), 0)
+       ok = bool(r0 != 0)
+       if !ok {
+               if e1 != 0 {
+                       errno = int(e1)
+               } else {
+                       errno = EINVAL
+               }
+       } else {
+               errno = 0
+       }
+       return
+}
+
 func WSAStartup(verreq uint32, data *WSAData) (sockerrno int) {
        r0, _, _ := Syscall(procWSAStartup, uintptr(verreq), uintptr(unsafe.Pointer(data)), 0)
        sockerrno = int(r0)
index 5c7545049ee2d3e567d22790d3a4c9372803f5d4..609b3801e93b60afaf916fdbce7204bed10ecb65 100644 (file)
@@ -25,6 +25,7 @@ const (
        ERROR_INSUFFICIENT_BUFFER = 122
        ERROR_MOD_NOT_FOUND       = 126
        ERROR_PROC_NOT_FOUND      = 127
+       ERROR_ENVVAR_NOT_FOUND    = 203
        ERROR_DIRECTORY           = 267
        ERROR_IO_PENDING          = 997
        // Go names for Windows errors.