Commit a108369c authored by Alexey Borzenkov's avatar Alexey Borzenkov Committed by Russ Cox

syscall: return EINVAL when string arguments have NUL characters

Since NUL usually terminates strings in underlying syscalls, allowing
it when converting string arguments is a security risk, especially
when dealing with filenames. For example, a program might reason that
filename like "/root/..\x00/" is a subdirectory or "/root/" and allow
access to it, while underlying syscall will treat "\x00" as an end of
that string and the actual filename will be "/root/..", which might
be unexpected. Returning EINVAL when string arguments have NUL in
them makes sure this attack vector is unusable.

R=golang-dev, r, bradfitz, fullung, rsc, minux.ma
CC=golang-dev
https://golang.org/cl/6458050
parent 8efb70f9
...@@ -98,9 +98,13 @@ func checkChainTrustStatus(c *Certificate, chainCtx *syscall.CertChainContext) e ...@@ -98,9 +98,13 @@ func checkChainTrustStatus(c *Certificate, chainCtx *syscall.CertChainContext) e
// checkChainSSLServerPolicy checks that the certificate chain in chainCtx is valid for // checkChainSSLServerPolicy checks that the certificate chain in chainCtx is valid for
// use as a certificate chain for a SSL/TLS server. // use as a certificate chain for a SSL/TLS server.
func checkChainSSLServerPolicy(c *Certificate, chainCtx *syscall.CertChainContext, opts *VerifyOptions) error { func checkChainSSLServerPolicy(c *Certificate, chainCtx *syscall.CertChainContext, opts *VerifyOptions) error {
servernamep, err := syscall.UTF16PtrFromString(opts.DNSName)
if err != nil {
return err
}
sslPara := &syscall.SSLExtraCertChainPolicyPara{ sslPara := &syscall.SSLExtraCertChainPolicyPara{
AuthType: syscall.AUTHTYPE_SERVER, AuthType: syscall.AUTHTYPE_SERVER,
ServerName: syscall.StringToUTF16Ptr(opts.DNSName), ServerName: servernamep,
} }
sslPara.Size = uint32(unsafe.Sizeof(*sslPara)) sslPara.Size = uint32(unsafe.Sizeof(*sslPara))
...@@ -110,7 +114,7 @@ func checkChainSSLServerPolicy(c *Certificate, chainCtx *syscall.CertChainContex ...@@ -110,7 +114,7 @@ func checkChainSSLServerPolicy(c *Certificate, chainCtx *syscall.CertChainContex
para.Size = uint32(unsafe.Sizeof(*para)) para.Size = uint32(unsafe.Sizeof(*para))
status := syscall.CertChainPolicyStatus{} status := syscall.CertChainPolicyStatus{}
err := syscall.CertVerifyCertificateChainPolicy(syscall.CERT_CHAIN_POLICY_SSL, chainCtx, para, &status) err = syscall.CertVerifyCertificateChainPolicy(syscall.CERT_CHAIN_POLICY_SSL, chainCtx, para, &status)
if err != nil { if err != nil {
return err return err
} }
......
...@@ -156,7 +156,11 @@ func (w *Watcher) wakeupReader() error { ...@@ -156,7 +156,11 @@ func (w *Watcher) wakeupReader() error {
} }
func getDir(pathname string) (dir string, err error) { func getDir(pathname string) (dir string, err error) {
attr, e := syscall.GetFileAttributes(syscall.StringToUTF16Ptr(pathname)) pathnamep, e := syscall.UTF16PtrFromString(pathname)
if e != nil {
return "", e
}
attr, e := syscall.GetFileAttributes(pathnamep)
if e != nil { if e != nil {
return "", os.NewSyscallError("GetFileAttributes", e) return "", os.NewSyscallError("GetFileAttributes", e)
} }
...@@ -170,7 +174,11 @@ func getDir(pathname string) (dir string, err error) { ...@@ -170,7 +174,11 @@ func getDir(pathname string) (dir string, err error) {
} }
func getIno(path string) (ino *inode, err error) { func getIno(path string) (ino *inode, err error) {
h, e := syscall.CreateFile(syscall.StringToUTF16Ptr(path), pathp, e := syscall.UTF16PtrFromString(path)
if e != nil {
return nil, e
}
h, e := syscall.CreateFile(pathp,
syscall.FILE_LIST_DIRECTORY, syscall.FILE_LIST_DIRECTORY,
syscall.FILE_SHARE_READ|syscall.FILE_SHARE_WRITE|syscall.FILE_SHARE_DELETE, syscall.FILE_SHARE_READ|syscall.FILE_SHARE_WRITE|syscall.FILE_SHARE_DELETE,
nil, syscall.OPEN_EXISTING, nil, syscall.OPEN_EXISTING,
......
...@@ -11,7 +11,8 @@ import ( ...@@ -11,7 +11,8 @@ import (
func initMime() { func initMime() {
var root syscall.Handle var root syscall.Handle
if syscall.RegOpenKeyEx(syscall.HKEY_CLASSES_ROOT, syscall.StringToUTF16Ptr(`\`), rootpathp, _ := syscall.UTF16PtrFromString(`\`)
if syscall.RegOpenKeyEx(syscall.HKEY_CLASSES_ROOT, rootpathp,
0, syscall.KEY_READ, &root) != nil { 0, syscall.KEY_READ, &root) != nil {
return return
} }
...@@ -31,15 +32,17 @@ func initMime() { ...@@ -31,15 +32,17 @@ func initMime() {
continue continue
} }
var h syscall.Handle var h syscall.Handle
extpathp, _ := syscall.UTF16PtrFromString(`\` + ext)
if syscall.RegOpenKeyEx( if syscall.RegOpenKeyEx(
syscall.HKEY_CLASSES_ROOT, syscall.StringToUTF16Ptr(`\`+ext), syscall.HKEY_CLASSES_ROOT, extpathp,
0, syscall.KEY_READ, &h) != nil { 0, syscall.KEY_READ, &h) != nil {
continue continue
} }
var typ uint32 var typ uint32
n = uint32(len(buf) * 2) // api expects array of bytes, not uint16 n = uint32(len(buf) * 2) // api expects array of bytes, not uint16
contenttypep, _ := syscall.UTF16PtrFromString("Content Type")
if syscall.RegQueryValueEx( if syscall.RegQueryValueEx(
h, syscall.StringToUTF16Ptr("Content Type"), h, contenttypep,
nil, &typ, (*byte)(unsafe.Pointer(&buf[0])), &n) != nil { nil, &typ, (*byte)(unsafe.Pointer(&buf[0])), &n) != nil {
syscall.RegCloseKey(h) syscall.RegCloseKey(h)
continue continue
......
...@@ -106,3 +106,27 @@ func TestIsExist(t *testing.T) { ...@@ -106,3 +106,27 @@ func TestIsExist(t *testing.T) {
} }
} }
} }
func TestErrPathNUL(t *testing.T) {
f, err := ioutil.TempFile("", "_Go_ErrPathNUL\x00")
if err == nil {
f.Close()
t.Fatal("TempFile should have failed")
}
f, err = ioutil.TempFile("", "_Go_ErrPathNUL")
if err != nil {
t.Fatalf("open ErrPathNUL tempfile: %s", err)
}
defer os.Remove(f.Name())
defer f.Close()
f2, err := os.OpenFile(f.Name(), os.O_RDWR, 0600)
if err != nil {
t.Fatalf("open ErrPathNUL: %s", err)
}
f2.Close()
f2, err = os.OpenFile(f.Name()+"\x00", os.O_RDWR, 0600)
if err == nil {
f2.Close()
t.Fatal("Open should have failed")
}
}
...@@ -77,8 +77,12 @@ func openFile(name string, flag int, perm FileMode) (file *File, err error) { ...@@ -77,8 +77,12 @@ func openFile(name string, flag int, perm FileMode) (file *File, err error) {
} }
func openDir(name string) (file *File, err error) { func openDir(name string) (file *File, err error) {
maskp, e := syscall.UTF16PtrFromString(name + `\*`)
if e != nil {
return nil, &PathError{"open", name, e}
}
d := new(dirInfo) d := new(dirInfo)
r, e := syscall.FindFirstFile(syscall.StringToUTF16Ptr(name+`\*`), &d.data) r, e := syscall.FindFirstFile(maskp, &d.data)
if e != nil { if e != nil {
return nil, &PathError{"open", name, e} return nil, &PathError{"open", name, e}
} }
...@@ -284,11 +288,14 @@ func Truncate(name string, size int64) error { ...@@ -284,11 +288,14 @@ func Truncate(name string, size int64) error {
// Remove removes the named file or directory. // Remove removes the named file or directory.
// If there is an error, it will be of type *PathError. // If there is an error, it will be of type *PathError.
func Remove(name string) error { func Remove(name string) error {
p := &syscall.StringToUTF16(name)[0] p, e := syscall.UTF16PtrFromString(name)
if e != nil {
return &PathError{"remove", name, e}
}
// Go file interface forces us to know whether // Go file interface forces us to know whether
// name is a file or directory. Try both. // name is a file or directory. Try both.
e := syscall.DeleteFile(p) e = syscall.DeleteFile(p)
if e == nil { if e == nil {
return nil return nil
} }
......
...@@ -48,7 +48,11 @@ func Stat(name string) (fi FileInfo, err error) { ...@@ -48,7 +48,11 @@ func Stat(name string) (fi FileInfo, err error) {
return statDevNull() return statDevNull()
} }
var d syscall.Win32FileAttributeData var d syscall.Win32FileAttributeData
e := syscall.GetFileAttributesEx(syscall.StringToUTF16Ptr(name), syscall.GetFileExInfoStandard, (*byte)(unsafe.Pointer(&d))) namep, e := syscall.UTF16PtrFromString(name)
if e != nil {
return nil, &PathError{"Stat", name, e}
}
e = syscall.GetFileAttributesEx(namep, syscall.GetFileExInfoStandard, (*byte)(unsafe.Pointer(&d)))
if e != nil { if e != nil {
return nil, &PathError{"GetFileAttributesEx", name, e} return nil, &PathError{"GetFileAttributesEx", name, e}
} }
...@@ -221,7 +225,11 @@ func (s *winSys) loadFileId() error { ...@@ -221,7 +225,11 @@ func (s *winSys) loadFileId() error {
} }
s.Lock() s.Lock()
defer s.Unlock() defer s.Unlock()
h, e := syscall.CreateFile(syscall.StringToUTF16Ptr(s.path), 0, 0, nil, syscall.OPEN_EXISTING, syscall.FILE_FLAG_BACKUP_SEMANTICS, 0) pathp, e := syscall.UTF16PtrFromString(s.path)
if e != nil {
return e
}
h, e := syscall.CreateFile(pathp, 0, 0, nil, syscall.OPEN_EXISTING, syscall.FILE_FLAG_BACKUP_SEMANTICS, 0)
if e != nil { if e != nil {
return e return e
} }
......
...@@ -16,10 +16,16 @@ func lookupFullName(domain, username, domainAndUser string) (string, error) { ...@@ -16,10 +16,16 @@ func lookupFullName(domain, username, domainAndUser string) (string, error) {
syscall.NameSamCompatible, syscall.NameDisplay, 50) syscall.NameSamCompatible, syscall.NameDisplay, 50)
if e != nil { if e != nil {
// domain lookup failed, perhaps this pc is not part of domain // domain lookup failed, perhaps this pc is not part of domain
d := syscall.StringToUTF16Ptr(domain) d, e := syscall.UTF16PtrFromString(domain)
u := syscall.StringToUTF16Ptr(username) if e != nil {
return "", e
}
u, e := syscall.UTF16PtrFromString(username)
if e != nil {
return "", e
}
var p *byte var p *byte
e := syscall.NetUserGetInfo(d, u, 10, &p) e = syscall.NetUserGetInfo(d, u, 10, &p)
if e != nil { if e != nil {
return "", e return "", e
} }
......
...@@ -9,7 +9,10 @@ import ( ...@@ -9,7 +9,10 @@ import (
) )
func toShort(path string) (string, error) { func toShort(path string) (string, error) {
p := syscall.StringToUTF16(path) p, err := syscall.UTF16FromString(path)
if err != nil {
return "", err
}
b := p // GetShortPathName says we can reuse buffer b := p // GetShortPathName says we can reuse buffer
n, err := syscall.GetShortPathName(&p[0], &b[0], uint32(len(b))) n, err := syscall.GetShortPathName(&p[0], &b[0], uint32(len(b)))
if err != nil { if err != nil {
...@@ -26,7 +29,10 @@ func toShort(path string) (string, error) { ...@@ -26,7 +29,10 @@ func toShort(path string) (string, error) {
} }
func toLong(path string) (string, error) { func toLong(path string) (string, error) {
p := syscall.StringToUTF16(path) p, err := syscall.UTF16FromString(path)
if err != nil {
return "", err
}
b := p // GetLongPathName says we can reuse buffer b := p // GetLongPathName says we can reuse buffer
n, err := syscall.GetLongPathName(&p[0], &b[0], uint32(len(b))) n, err := syscall.GetLongPathName(&p[0], &b[0], uint32(len(b)))
if err != nil { if err != nil {
......
...@@ -112,9 +112,10 @@ func Test64BitReturnStdCall(t *testing.T) { ...@@ -112,9 +112,10 @@ func Test64BitReturnStdCall(t *testing.T) {
func TestCDecl(t *testing.T) { func TestCDecl(t *testing.T) {
var buf [50]byte var buf [50]byte
fmtp, _ := syscall.BytePtrFromString("%d %d %d")
a, _, _ := GetDLL(t, "user32.dll").Proc("wsprintfA").Call( a, _, _ := GetDLL(t, "user32.dll").Proc("wsprintfA").Call(
uintptr(unsafe.Pointer(&buf[0])), uintptr(unsafe.Pointer(&buf[0])),
uintptr(unsafe.Pointer(syscall.StringBytePtr("%d %d %d"))), uintptr(unsafe.Pointer(fmtp)),
1000, 2000, 3000) 1000, 2000, 3000)
if string(buf[:a]) != "1000 2000 3000" { if string(buf[:a]) != "1000 2000 3000" {
t.Error("cdecl USER32.wsprintfA returns", a, "buf=", buf[:a]) t.Error("cdecl USER32.wsprintfA returns", a, "buf=", buf[:a])
......
...@@ -34,7 +34,11 @@ type DLL struct { ...@@ -34,7 +34,11 @@ type DLL struct {
// LoadDLL loads DLL file into memory. // LoadDLL loads DLL file into memory.
func LoadDLL(name string) (dll *DLL, err error) { func LoadDLL(name string) (dll *DLL, err error) {
h, e := loadlibrary(StringToUTF16Ptr(name)) namep, err := UTF16PtrFromString(name)
if err != nil {
return nil, err
}
h, e := loadlibrary(namep)
if e != 0 { if e != 0 {
return nil, &DLLError{ return nil, &DLLError{
Err: e, Err: e,
...@@ -61,7 +65,11 @@ func MustLoadDLL(name string) *DLL { ...@@ -61,7 +65,11 @@ func MustLoadDLL(name string) *DLL {
// FindProc searches DLL d for procedure named name and returns *Proc // FindProc searches DLL d for procedure named name and returns *Proc
// if found. It returns an error if search fails. // if found. It returns an error if search fails.
func (d *DLL) FindProc(name string) (proc *Proc, err error) { func (d *DLL) FindProc(name string) (proc *Proc, err error) {
a, e := getprocaddress(uintptr(d.Handle), StringBytePtr(name)) namep, err := BytePtrFromString(name)
if err != nil {
return nil, err
}
a, e := getprocaddress(uintptr(d.Handle), namep)
if e != 0 { if e != 0 {
return nil, &DLLError{ return nil, &DLLError{
Err: e, Err: e,
......
...@@ -12,14 +12,18 @@ import ( ...@@ -12,14 +12,18 @@ import (
) )
func Getenv(key string) (value string, found bool) { func Getenv(key string) (value string, found bool) {
keyp, err := UTF16PtrFromString(key)
if err != nil {
return "", false
}
b := make([]uint16, 100) b := make([]uint16, 100)
n, e := GetEnvironmentVariable(StringToUTF16Ptr(key), &b[0], uint32(len(b))) n, e := GetEnvironmentVariable(keyp, &b[0], uint32(len(b)))
if n == 0 && e == ERROR_ENVVAR_NOT_FOUND { if n == 0 && e == ERROR_ENVVAR_NOT_FOUND {
return "", false return "", false
} }
if n > uint32(len(b)) { if n > uint32(len(b)) {
b = make([]uint16, n) b = make([]uint16, n)
n, e = GetEnvironmentVariable(StringToUTF16Ptr(key), &b[0], uint32(len(b))) n, e = GetEnvironmentVariable(keyp, &b[0], uint32(len(b)))
if n > uint32(len(b)) { if n > uint32(len(b)) {
n = 0 n = 0
} }
...@@ -32,10 +36,18 @@ func Getenv(key string) (value string, found bool) { ...@@ -32,10 +36,18 @@ func Getenv(key string) (value string, found bool) {
func Setenv(key, value string) error { func Setenv(key, value string) error {
var v *uint16 var v *uint16
var err error
if len(value) > 0 { if len(value) > 0 {
v = StringToUTF16Ptr(value) v, err = UTF16PtrFromString(value)
if err != nil {
return err
}
}
keyp, err := UTF16PtrFromString(key)
if err != nil {
return err
} }
e := SetEnvironmentVariable(StringToUTF16Ptr(key), v) e := SetEnvironmentVariable(keyp, v)
if e != nil { if e != nil {
return e return e
} }
......
...@@ -60,8 +60,9 @@ import ( ...@@ -60,8 +60,9 @@ import (
var ForkLock sync.RWMutex var ForkLock sync.RWMutex
// Convert array of string to array // StringSlicePtr is deprecated. Use SlicePtrFromStrings instead.
// of NUL-terminated byte pointer. // If any string contains a NUL byte this function panics instead
// of returning an error.
func StringSlicePtr(ss []string) []*byte { func StringSlicePtr(ss []string) []*byte {
bb := make([]*byte, len(ss)+1) bb := make([]*byte, len(ss)+1)
for i := 0; i < len(ss); i++ { for i := 0; i < len(ss); i++ {
...@@ -71,6 +72,22 @@ func StringSlicePtr(ss []string) []*byte { ...@@ -71,6 +72,22 @@ func StringSlicePtr(ss []string) []*byte {
return bb return bb
} }
// SlicePtrFromStrings converts a slice of strings to a slice of
// pointers to NUL-terminated byte slices. If any string contains
// a NUL byte, it returns (nil, EINVAL).
func SlicePtrFromStrings(ss []string) ([]*byte, error) {
var err error
bb := make([]*byte, len(ss)+1)
for i := 0; i < len(ss); i++ {
bb[i], err = BytePtrFromString(ss[i])
if err != nil {
return nil, err
}
}
bb[len(ss)] = nil
return bb, nil
}
// gbit16 reads a 16-bit numeric value from a 9P protocol message stored in b, // gbit16 reads a 16-bit numeric value from a 9P protocol message stored in b,
// returning the value and the remaining slice of b. // returning the value and the remaining slice of b.
func gbit16(b []byte) (uint16, []byte) { func gbit16(b []byte) (uint16, []byte) {
...@@ -373,12 +390,21 @@ func forkExec(argv0 string, argv []string, attr *ProcAttr) (pid int, err error) ...@@ -373,12 +390,21 @@ func forkExec(argv0 string, argv []string, attr *ProcAttr) (pid int, err error)
p[1] = -1 p[1] = -1
// Convert args to C form. // Convert args to C form.
argv0p := StringBytePtr(argv0) argv0p, err := BytePtrFromString(argv0)
argvp := StringSlicePtr(argv) if err != nil {
return 0, err
}
argvp, err := SlicePtrFromStrings(argv)
if err != nil {
return 0, err
}
var dir *byte var dir *byte
if attr.Dir != "" { if attr.Dir != "" {
dir = StringBytePtr(attr.Dir) dir, err = BytePtrFromString(attr.Dir)
if err != nil {
return 0, err
}
} }
var envvParsed []envItem var envvParsed []envItem
if attr.Env != nil { if attr.Env != nil {
...@@ -389,7 +415,15 @@ func forkExec(argv0 string, argv []string, attr *ProcAttr) (pid int, err error) ...@@ -389,7 +415,15 @@ func forkExec(argv0 string, argv []string, attr *ProcAttr) (pid int, err error)
i++ i++
} }
envvParsed = append(envvParsed, envItem{StringBytePtr("/env/" + v[:i]), StringBytePtr(v[i+1:]), len(v) - i}) envname, err := BytePtrFromString("/env/" + v[:i])
if err != nil {
return 0, err
}
envvalue, err := BytePtrFromString(v[i+1:])
if err != nil {
return 0, err
}
envvParsed = append(envvParsed, envItem{envname, envvalue, len(v) - i})
} }
} }
...@@ -511,9 +545,17 @@ func Exec(argv0 string, argv []string, envv []string) (err error) { ...@@ -511,9 +545,17 @@ func Exec(argv0 string, argv []string, envv []string) (err error) {
} }
} }
argv0p, err := BytePtrFromString(argv0)
if err != nil {
return err
}
argvp, err := SlicePtrFromStrings(argv)
if err != nil {
return err
}
_, _, e1 := Syscall(SYS_EXEC, _, _, e1 := Syscall(SYS_EXEC,
uintptr(unsafe.Pointer(StringBytePtr(argv0))), uintptr(unsafe.Pointer(argv0p)),
uintptr(unsafe.Pointer(&StringSlicePtr(argv)[0])), uintptr(unsafe.Pointer(&argvp[0])),
0) 0)
return e1 return e1
......
...@@ -63,8 +63,9 @@ import ( ...@@ -63,8 +63,9 @@ import (
var ForkLock sync.RWMutex var ForkLock sync.RWMutex
// Convert array of string to array // StringSlicePtr is deprecated. Use SlicePtrFromStrings instead.
// of NUL-terminated byte pointer. // If any string contains a NUL byte this function panics instead
// of returning an error.
func StringSlicePtr(ss []string) []*byte { func StringSlicePtr(ss []string) []*byte {
bb := make([]*byte, len(ss)+1) bb := make([]*byte, len(ss)+1)
for i := 0; i < len(ss); i++ { for i := 0; i < len(ss); i++ {
...@@ -74,6 +75,22 @@ func StringSlicePtr(ss []string) []*byte { ...@@ -74,6 +75,22 @@ func StringSlicePtr(ss []string) []*byte {
return bb return bb
} }
// SlicePtrFromStrings converts a slice of strings to a slice of
// pointers to NUL-terminated byte slices. If any string contains
// a NUL byte, it returns (nil, EINVAL).
func SlicePtrFromStrings(ss []string) ([]*byte, error) {
var err error
bb := make([]*byte, len(ss)+1)
for i := 0; i < len(ss); i++ {
bb[i], err = BytePtrFromString(ss[i])
if err != nil {
return nil, err
}
}
bb[len(ss)] = nil
return bb, nil
}
func CloseOnExec(fd int) { fcntl(fd, F_SETFD, FD_CLOEXEC) } func CloseOnExec(fd int) { fcntl(fd, F_SETFD, FD_CLOEXEC) }
func SetNonblock(fd int, nonblocking bool) (err error) { func SetNonblock(fd int, nonblocking bool) (err error) {
...@@ -128,9 +145,18 @@ func forkExec(argv0 string, argv []string, attr *ProcAttr) (pid int, err error) ...@@ -128,9 +145,18 @@ func forkExec(argv0 string, argv []string, attr *ProcAttr) (pid int, err error)
p[1] = -1 p[1] = -1
// Convert args to C form. // Convert args to C form.
argv0p := StringBytePtr(argv0) argv0p, err := BytePtrFromString(argv0)
argvp := StringSlicePtr(argv) if err != nil {
envvp := StringSlicePtr(attr.Env) return 0, err
}
argvp, err := SlicePtrFromStrings(argv)
if err != nil {
return 0, err
}
envvp, err := SlicePtrFromStrings(attr.Env)
if err != nil {
return 0, err
}
if runtime.GOOS == "freebsd" && len(argv[0]) > len(argv0) { if runtime.GOOS == "freebsd" && len(argv[0]) > len(argv0) {
argvp[0] = argv0p argvp[0] = argv0p
...@@ -138,11 +164,17 @@ func forkExec(argv0 string, argv []string, attr *ProcAttr) (pid int, err error) ...@@ -138,11 +164,17 @@ func forkExec(argv0 string, argv []string, attr *ProcAttr) (pid int, err error)
var chroot *byte var chroot *byte
if sys.Chroot != "" { if sys.Chroot != "" {
chroot = StringBytePtr(sys.Chroot) chroot, err = BytePtrFromString(sys.Chroot)
if err != nil {
return 0, err
}
} }
var dir *byte var dir *byte
if attr.Dir != "" { if attr.Dir != "" {
dir = StringBytePtr(attr.Dir) dir, err = BytePtrFromString(attr.Dir)
if err != nil {
return 0, err
}
} }
// Acquire the fork lock so that no other threads // Acquire the fork lock so that no other threads
...@@ -215,9 +247,21 @@ func StartProcess(argv0 string, argv []string, attr *ProcAttr) (pid int, handle ...@@ -215,9 +247,21 @@ func StartProcess(argv0 string, argv []string, attr *ProcAttr) (pid int, handle
// Ordinary exec. // Ordinary exec.
func Exec(argv0 string, argv []string, envv []string) (err error) { func Exec(argv0 string, argv []string, envv []string) (err error) {
argv0p, err := BytePtrFromString(argv0)
if err != nil {
return err
}
argvp, err := SlicePtrFromStrings(argv)
if err != nil {
return err
}
envvp, err := SlicePtrFromStrings(envv)
if err != nil {
return err
}
_, _, err1 := RawSyscall(SYS_EXECVE, _, _, err1 := RawSyscall(SYS_EXECVE,
uintptr(unsafe.Pointer(StringBytePtr(argv0))), uintptr(unsafe.Pointer(argv0p)),
uintptr(unsafe.Pointer(&StringSlicePtr(argv)[0])), uintptr(unsafe.Pointer(&argvp[0])),
uintptr(unsafe.Pointer(&StringSlicePtr(envv)[0]))) uintptr(unsafe.Pointer(&envvp[0])))
return Errno(err1) return Errno(err1)
} }
...@@ -132,7 +132,10 @@ func SetNonblock(fd Handle, nonblocking bool) (err error) { ...@@ -132,7 +132,10 @@ func SetNonblock(fd Handle, nonblocking bool) (err error) {
// getFullPath retrieves the full path of the specified file. // getFullPath retrieves the full path of the specified file.
// Just a wrapper for Windows GetFullPathName api. // Just a wrapper for Windows GetFullPathName api.
func getFullPath(name string) (path string, err error) { func getFullPath(name string) (path string, err error) {
p := StringToUTF16Ptr(name) p, err := UTF16PtrFromString(name)
if err != nil {
return "", err
}
buf := make([]uint16, 100) buf := make([]uint16, 100)
n, err := GetFullPathName(p, uint32(len(buf)), &buf[0], nil) n, err := GetFullPathName(p, uint32(len(buf)), &buf[0], nil)
if err != nil { if err != nil {
...@@ -262,7 +265,10 @@ func StartProcess(argv0 string, argv []string, attr *ProcAttr) (pid int, handle ...@@ -262,7 +265,10 @@ func StartProcess(argv0 string, argv []string, attr *ProcAttr) (pid int, handle
return 0, 0, err return 0, 0, err
} }
} }
argv0p := StringToUTF16Ptr(argv0) argv0p, err := UTF16PtrFromString(argv0)
if err != nil {
return 0, 0, err
}
var cmdline string var cmdline string
// Windows CreateProcess takes the command line as a single string: // Windows CreateProcess takes the command line as a single string:
...@@ -276,12 +282,18 @@ func StartProcess(argv0 string, argv []string, attr *ProcAttr) (pid int, handle ...@@ -276,12 +282,18 @@ func StartProcess(argv0 string, argv []string, attr *ProcAttr) (pid int, handle
var argvp *uint16 var argvp *uint16
if len(cmdline) != 0 { if len(cmdline) != 0 {
argvp = StringToUTF16Ptr(cmdline) argvp, err = UTF16PtrFromString(cmdline)
if err != nil {
return 0, 0, err
}
} }
var dirp *uint16 var dirp *uint16
if len(attr.Dir) != 0 { if len(attr.Dir) != 0 {
dirp = StringToUTF16Ptr(attr.Dir) dirp, err = UTF16PtrFromString(attr.Dir)
if err != nil {
return 0, 0, err
}
} }
// Acquire the fork lock so that no other threads // Acquire the fork lock so that no other threads
......
...@@ -110,6 +110,16 @@ while(<>) { ...@@ -110,6 +110,16 @@ while(<>) {
my $out_decl = @out ? sprintf(" (%s)", join(', ', @out)) : ""; my $out_decl = @out ? sprintf(" (%s)", join(', ', @out)) : "";
$text .= sprintf "func %s(%s)%s {\n", $func, join(', ', @in), $out_decl; $text .= sprintf "func %s(%s)%s {\n", $func, join(', ', @in), $out_decl;
# Check if err return available
my $errvar = "";
foreach my $p (@out) {
my ($name, $type) = parseparam($p);
if($type eq "error") {
$errvar = $name;
last;
}
}
# Prepare arguments to Syscall. # Prepare arguments to Syscall.
my @args = (); my @args = ();
my $n = 0; my $n = 0;
...@@ -117,8 +127,18 @@ while(<>) { ...@@ -117,8 +127,18 @@ while(<>) {
my ($name, $type) = parseparam($p); my ($name, $type) = parseparam($p);
if($type =~ /^\*/) { if($type =~ /^\*/) {
push @args, "uintptr(unsafe.Pointer($name))"; push @args, "uintptr(unsafe.Pointer($name))";
} elsif($type eq "string" && $errvar ne "") {
$text .= "\tvar _p$n *byte\n";
$text .= "\t_p$n, $errvar = BytePtrFromString($name)\n";
$text .= "\tif $errvar != nil {\n\t\treturn\n\t}\n";
push @args, "uintptr(unsafe.Pointer(_p$n))";
$n++;
} elsif($type eq "string") { } elsif($type eq "string") {
push @args, "uintptr(unsafe.Pointer(StringBytePtr($name)))"; print STDERR "$ARGV:$.: $func uses string arguments, but has no error return\n";
$text .= "\tvar _p$n *byte\n";
$text .= "\t_p$n, _ = BytePtrFromString($name)\n";
push @args, "uintptr(unsafe.Pointer(_p$n))";
$n++;
} elsif($type =~ /^\[\](.*)/) { } elsif($type =~ /^\[\](.*)/) {
# Convert slice into pointer, length. # Convert slice into pointer, length.
# Have to be careful not to take address of &a[0] if len == 0: # Have to be careful not to take address of &a[0] if len == 0:
......
...@@ -118,7 +118,8 @@ while(<>) { ...@@ -118,7 +118,8 @@ while(<>) {
} }
# Decide which version of api is used: ascii or unicode. # Decide which version of api is used: ascii or unicode.
my $strconvfunc = $sysname !~ /W$/ ? "StringBytePtr" : "StringToUTF16Ptr"; my $strconvfunc = $sysname !~ /W$/ ? "BytePtrFromString" : "UTF16PtrFromString";
my $strconvtype = $sysname !~ /W$/ ? "*byte" : "*uint16";
# Winapi proc address variable. # Winapi proc address variable.
$vars .= "\t$sysvarname = $modvname.NewProc(\"$sysname\")\n"; $vars .= "\t$sysvarname = $modvname.NewProc(\"$sysname\")\n";
...@@ -133,6 +134,16 @@ while(<>) { ...@@ -133,6 +134,16 @@ while(<>) {
} }
$text .= sprintf "func %s(%s)%s {\n", $func, join(', ', @in), $out; $text .= sprintf "func %s(%s)%s {\n", $func, join(', ', @in), $out;
# Check if err return available
my $errvar = "";
foreach my $p (@out) {
my ($name, $type) = parseparam($p);
if($type eq "error") {
$errvar = $name;
last;
}
}
# Prepare arguments to Syscall. # Prepare arguments to Syscall.
my @args = (); my @args = ();
my $n = 0; my $n = 0;
...@@ -141,8 +152,18 @@ while(<>) { ...@@ -141,8 +152,18 @@ while(<>) {
my ($name, $type) = parseparam($p); my ($name, $type) = parseparam($p);
if($type =~ /^\*/) { if($type =~ /^\*/) {
push @args, "uintptr(unsafe.Pointer($name))"; push @args, "uintptr(unsafe.Pointer($name))";
} elsif($type eq "string" && $errvar ne "") {
$text .= "\tvar _p$n $strconvtype\n";
$text .= "\t_p$n, $errvar = $strconvfunc($name)\n";
$text .= "\tif $errvar != nil {\n\t\treturn\n\t}\n";
push @args, "uintptr(unsafe.Pointer(_p$n))";
$n++;
} elsif($type eq "string") { } elsif($type eq "string") {
push @args, "uintptr(unsafe.Pointer($strconvfunc($name)))"; print STDERR "$ARGV:$.: $func uses string arguments, but has no error return\n";
$text .= "\tvar _p$n $strconvtype\n";
$text .= "\t_p$n, _ = $strconvfunc($name)\n";
push @args, "uintptr(unsafe.Pointer(_p$n))";
$n++;
} elsif($type =~ /^\[\](.*)/) { } elsif($type =~ /^\[\](.*)/) {
# Convert slice into pointer, length. # Convert slice into pointer, length.
# Have to be careful not to take address of &a[0] if len == 0: # Have to be careful not to take address of &a[0] if len == 0:
......
...@@ -37,10 +37,13 @@ const ( ...@@ -37,10 +37,13 @@ const (
// TranslateAccountName converts a directory service // TranslateAccountName converts a directory service
// object name from one format to another. // object name from one format to another.
func TranslateAccountName(username string, from, to uint32, initSize int) (string, error) { func TranslateAccountName(username string, from, to uint32, initSize int) (string, error) {
u := StringToUTF16Ptr(username) u, e := UTF16PtrFromString(username)
if e != nil {
return "", e
}
b := make([]uint16, 50) b := make([]uint16, 50)
n := uint32(len(b)) n := uint32(len(b))
e := TranslateName(u, from, to, &b[0], &n) e = TranslateName(u, from, to, &b[0], &n)
if e != nil { if e != nil {
if e != ERROR_INSUFFICIENT_BUFFER { if e != ERROR_INSUFFICIENT_BUFFER {
return "", e return "", e
...@@ -94,7 +97,11 @@ type SID struct{} ...@@ -94,7 +97,11 @@ type SID struct{}
// sid into a valid, functional sid. // sid into a valid, functional sid.
func StringToSid(s string) (*SID, error) { func StringToSid(s string) (*SID, error) {
var sid *SID var sid *SID
e := ConvertStringSidToSid(StringToUTF16Ptr(s), &sid) p, e := UTF16PtrFromString(s)
if e != nil {
return nil, e
}
e = ConvertStringSidToSid(p, &sid)
if e != nil { if e != nil {
return nil, e return nil, e
} }
...@@ -109,17 +116,23 @@ func LookupSID(system, account string) (sid *SID, domain string, accType uint32, ...@@ -109,17 +116,23 @@ func LookupSID(system, account string) (sid *SID, domain string, accType uint32,
if len(account) == 0 { if len(account) == 0 {
return nil, "", 0, EINVAL return nil, "", 0, EINVAL
} }
acc := StringToUTF16Ptr(account) acc, e := UTF16PtrFromString(account)
if e != nil {
return nil, "", 0, e
}
var sys *uint16 var sys *uint16
if len(system) > 0 { if len(system) > 0 {
sys = StringToUTF16Ptr(system) sys, e = UTF16PtrFromString(system)
if e != nil {
return nil, "", 0, e
}
} }
db := make([]uint16, 50) db := make([]uint16, 50)
dn := uint32(len(db)) dn := uint32(len(db))
b := make([]byte, 50) b := make([]byte, 50)
n := uint32(len(b)) n := uint32(len(b))
sid = (*SID)(unsafe.Pointer(&b[0])) sid = (*SID)(unsafe.Pointer(&b[0]))
e := LookupAccountName(sys, acc, sid, &n, &db[0], &dn, &accType) e = LookupAccountName(sys, acc, sid, &n, &db[0], &dn, &accType)
if e != nil { if e != nil {
if e != ERROR_INSUFFICIENT_BUFFER { if e != ERROR_INSUFFICIENT_BUFFER {
return nil, "", 0, e return nil, "", 0, e
...@@ -170,7 +183,10 @@ func (sid *SID) Copy() (*SID, error) { ...@@ -170,7 +183,10 @@ func (sid *SID) Copy() (*SID, error) {
func (sid *SID) LookupAccount(system string) (account, domain string, accType uint32, err error) { func (sid *SID) LookupAccount(system string) (account, domain string, accType uint32, err error) {
var sys *uint16 var sys *uint16
if len(system) > 0 { if len(system) > 0 {
sys = StringToUTF16Ptr(system) sys, err = UTF16PtrFromString(system)
if err != nil {
return "", "", 0, err
}
} }
b := make([]uint16, 50) b := make([]uint16, 50)
n := uint32(len(b)) n := uint32(len(b))
......
...@@ -14,18 +14,47 @@ ...@@ -14,18 +14,47 @@
// On most systems, that error has type syscall.Errno. // On most systems, that error has type syscall.Errno.
package syscall package syscall
// StringByteSlice returns a NUL-terminated slice of bytes // StringByteSlice is deprecated. Use ByteSliceFromString instead.
// containing the text of s. // If s contains a NUL byte this function panics instead of
// returning an error.
func StringByteSlice(s string) []byte { func StringByteSlice(s string) []byte {
a, err := ByteSliceFromString(s)
if err != nil {
panic("syscall: string with NUL passed to StringByteSlice")
}
return a
}
// ByteSliceFromString returns a NUL-terminated slice of bytes
// containing the text of s. If s contains a NUL byte at any
// location, it returns (nil, EINVAL).
func ByteSliceFromString(s string) ([]byte, error) {
for i := 0; i < len(s); i++ {
if s[i] == 0 {
return nil, EINVAL
}
}
a := make([]byte, len(s)+1) a := make([]byte, len(s)+1)
copy(a, s) copy(a, s)
return a return a, nil
} }
// StringBytePtr returns a pointer to a NUL-terminated array of bytes // StringBytePtr is deprecated. Use BytePtrFromString instead.
// containing the text of s. // If s contains a NUL byte this function panics instead of
// returning an error.
func StringBytePtr(s string) *byte { return &StringByteSlice(s)[0] } func StringBytePtr(s string) *byte { return &StringByteSlice(s)[0] }
// BytePtrFromString returns a pointer to a NUL-terminated array of
// bytes containing the text of s. If s contains a NUL byte at any
// location, it returns (nil, EINVAL).
func BytePtrFromString(s string) (*byte, error) {
a, err := ByteSliceFromString(s)
if err != nil {
return nil, err
}
return &a[0], nil
}
// Single-word zero for use when we need a valid pointer to 0 bytes. // Single-word zero for use when we need a valid pointer to 0 bytes.
// See mksyscall.pl. // See mksyscall.pl.
var _zero uintptr var _zero uintptr
......
...@@ -41,7 +41,10 @@ func nametomib(name string) (mib []_C_int, err error) { ...@@ -41,7 +41,10 @@ func nametomib(name string) (mib []_C_int, err error) {
n := uintptr(CTL_MAXNAME) * siz n := uintptr(CTL_MAXNAME) * siz
p := (*byte)(unsafe.Pointer(&buf[0])) p := (*byte)(unsafe.Pointer(&buf[0]))
bytes := StringByteSlice(name) bytes, err := ByteSliceFromString(name)
if err != nil {
return nil, err
}
// Magic sysctl: "setting" 0.3 to a string name // Magic sysctl: "setting" 0.3 to a string name
// lets you read back the array of integers form. // lets you read back the array of integers form.
......
...@@ -41,7 +41,10 @@ func nametomib(name string) (mib []_C_int, err error) { ...@@ -41,7 +41,10 @@ func nametomib(name string) (mib []_C_int, err error) {
n := uintptr(CTL_MAXNAME) * siz n := uintptr(CTL_MAXNAME) * siz
p := (*byte)(unsafe.Pointer(&buf[0])) p := (*byte)(unsafe.Pointer(&buf[0]))
bytes := StringByteSlice(name) bytes, err := ByteSliceFromString(name)
if err != nil {
return nil, err
}
// Magic sysctl: "setting" 0.3 to a string name // Magic sysctl: "setting" 0.3 to a string name
// lets you read back the array of integers form. // lets you read back the array of integers form.
......
...@@ -52,7 +52,11 @@ func Futimesat(dirfd int, path string, tv []Timeval) (err error) { ...@@ -52,7 +52,11 @@ func Futimesat(dirfd int, path string, tv []Timeval) (err error) {
if len(tv) != 2 { if len(tv) != 2 {
return EINVAL return EINVAL
} }
return futimesat(dirfd, StringBytePtr(path), (*[2]Timeval)(unsafe.Pointer(&tv[0]))) pathp, err := BytePtrFromString(path)
if err != nil {
return err
}
return futimesat(dirfd, pathp, (*[2]Timeval)(unsafe.Pointer(&tv[0])))
} }
func Futimes(fd int, tv []Timeval) (err error) { func Futimes(fd int, tv []Timeval) (err error) {
...@@ -783,7 +787,11 @@ func Mount(source string, target string, fstype string, flags uintptr, data stri ...@@ -783,7 +787,11 @@ func Mount(source string, target string, fstype string, flags uintptr, data stri
if data == "" { if data == "" {
return mount(source, target, fstype, flags, nil) return mount(source, target, fstype, flags, nil)
} }
return mount(source, target, fstype, flags, StringBytePtr(data)) datap, err := BytePtrFromString(data)
if err != nil {
return err
}
return mount(source, target, fstype, flags, datap)
} }
// Sendto // Sendto
......
...@@ -306,7 +306,11 @@ func Fstatfs(fd int, buf *Statfs_t) (err error) { ...@@ -306,7 +306,11 @@ func Fstatfs(fd int, buf *Statfs_t) (err error) {
} }
func Statfs(path string, buf *Statfs_t) (err error) { func Statfs(path string, buf *Statfs_t) (err error) {
_, _, e := Syscall(SYS_STATFS64, uintptr(unsafe.Pointer(StringBytePtr(path))), unsafe.Sizeof(*buf), uintptr(unsafe.Pointer(buf))) pathp, err := BytePtrFromString(path)
if err != nil {
return err
}
_, _, e := Syscall(SYS_STATFS64, uintptr(unsafe.Pointer(pathp)), unsafe.Sizeof(*buf), uintptr(unsafe.Pointer(buf)))
if e != 0 { if e != 0 {
err = e err = e
} }
......
...@@ -237,16 +237,24 @@ func Await(w *Waitmsg) (err error) { ...@@ -237,16 +237,24 @@ func Await(w *Waitmsg) (err error) {
} }
func Unmount(name, old string) (err error) { func Unmount(name, old string) (err error) {
oldp := uintptr(unsafe.Pointer(StringBytePtr(old))) oldp, err := BytePtrFromString(old)
if err != nil {
return err
}
oldptr := uintptr(unsafe.Pointer(oldp))
var r0 uintptr var r0 uintptr
var e ErrorString var e ErrorString
// bind(2) man page: If name is zero, everything bound or mounted upon old is unbound or unmounted. // bind(2) man page: If name is zero, everything bound or mounted upon old is unbound or unmounted.
if name == "" { if name == "" {
r0, _, e = Syscall(SYS_UNMOUNT, _zero, oldp, 0) r0, _, e = Syscall(SYS_UNMOUNT, _zero, oldptr, 0)
} else { } else {
r0, _, e = Syscall(SYS_UNMOUNT, uintptr(unsafe.Pointer(StringBytePtr(name))), oldp, 0) namep, err := BytePtrFromString(name)
if err != nil {
return err
}
r0, _, e = Syscall(SYS_UNMOUNT, uintptr(unsafe.Pointer(namep)), oldptr, 0)
} }
if int(r0) == -1 { if int(r0) == -1 {
......
...@@ -52,9 +52,28 @@ func main() { ...@@ -52,9 +52,28 @@ func main() {
*/ */
// StringToUTF16 returns the UTF-16 encoding of the UTF-8 string s, // StringToUTF16 is deprecated. Use UTF16FromString instead.
// with a terminating NUL added. // If s contains a NUL byte this function panics instead of
func StringToUTF16(s string) []uint16 { return utf16.Encode([]rune(s + "\x00")) } // returning an error.
func StringToUTF16(s string) []uint16 {
a, err := UTF16FromString(s)
if err != nil {
panic("syscall: 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, EINVAL).
func UTF16FromString(s string) ([]uint16, error) {
for i := 0; i < len(s); i++ {
if s[i] == 0 {
return nil, EINVAL
}
}
return utf16.Encode([]rune(s + "\x00")), nil
}
// UTF16ToString returns the UTF-8 encoding of the UTF-16 sequence s, // UTF16ToString returns the UTF-8 encoding of the UTF-16 sequence s,
// with a terminating NUL removed. // with a terminating NUL removed.
...@@ -68,10 +87,22 @@ func UTF16ToString(s []uint16) string { ...@@ -68,10 +87,22 @@ func UTF16ToString(s []uint16) string {
return string(utf16.Decode(s)) return string(utf16.Decode(s))
} }
// StringToUTF16Ptr returns pointer to the UTF-16 encoding of // StringToUTF16Ptr is deprecated. Use UTF16PtrFromString instead.
// the UTF-8 string s, with a terminating NUL added. // If s contains a NUL byte this function panics instead of
// returning an error.
func StringToUTF16Ptr(s string) *uint16 { return &StringToUTF16(s)[0] } 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, 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 } func Getpagesize() int { return 4096 }
// Errno is the Windows error number. // Errno is the Windows error number.
...@@ -218,6 +249,10 @@ func Open(path string, mode int, perm uint32) (fd Handle, err error) { ...@@ -218,6 +249,10 @@ func Open(path string, mode int, perm uint32) (fd Handle, err error) {
if len(path) == 0 { if len(path) == 0 {
return InvalidHandle, ERROR_FILE_NOT_FOUND return InvalidHandle, ERROR_FILE_NOT_FOUND
} }
pathp, err := UTF16PtrFromString(path)
if err != nil {
return InvalidHandle, err
}
var access uint32 var access uint32
switch mode & (O_RDONLY | O_WRONLY | O_RDWR) { switch mode & (O_RDONLY | O_WRONLY | O_RDWR) {
case O_RDONLY: case O_RDONLY:
...@@ -252,7 +287,7 @@ func Open(path string, mode int, perm uint32) (fd Handle, err error) { ...@@ -252,7 +287,7 @@ func Open(path string, mode int, perm uint32) (fd Handle, err error) {
default: default:
createmode = OPEN_EXISTING createmode = OPEN_EXISTING
} }
h, e := CreateFile(StringToUTF16Ptr(path), access, sharemode, sa, createmode, FILE_ATTRIBUTE_NORMAL, 0) h, e := CreateFile(pathp, access, sharemode, sa, createmode, FILE_ATTRIBUTE_NORMAL, 0)
return h, e return h, e
} }
...@@ -330,24 +365,46 @@ func Getwd() (wd string, err error) { ...@@ -330,24 +365,46 @@ func Getwd() (wd string, err error) {
} }
func Chdir(path string) (err error) { func Chdir(path string) (err error) {
return SetCurrentDirectory(&StringToUTF16(path)[0]) pathp, err := UTF16PtrFromString(path)
if err != nil {
return err
}
return SetCurrentDirectory(pathp)
} }
func Mkdir(path string, mode uint32) (err error) { func Mkdir(path string, mode uint32) (err error) {
return CreateDirectory(&StringToUTF16(path)[0], nil) pathp, err := UTF16PtrFromString(path)
if err != nil {
return err
}
return CreateDirectory(pathp, nil)
} }
func Rmdir(path string) (err error) { func Rmdir(path string) (err error) {
return RemoveDirectory(&StringToUTF16(path)[0]) pathp, err := UTF16PtrFromString(path)
if err != nil {
return err
}
return RemoveDirectory(pathp)
} }
func Unlink(path string) (err error) { func Unlink(path string) (err error) {
return DeleteFile(&StringToUTF16(path)[0]) pathp, err := UTF16PtrFromString(path)
if err != nil {
return err
}
return DeleteFile(pathp)
} }
func Rename(oldpath, newpath string) (err error) { func Rename(oldpath, newpath string) (err error) {
from := &StringToUTF16(oldpath)[0] from, err := UTF16PtrFromString(oldpath)
to := &StringToUTF16(newpath)[0] if err != nil {
return err
}
to, err := UTF16PtrFromString(newpath)
if err != nil {
return err
}
return MoveFile(from, to) return MoveFile(from, to)
} }
...@@ -403,7 +460,11 @@ func Utimes(path string, tv []Timeval) (err error) { ...@@ -403,7 +460,11 @@ func Utimes(path string, tv []Timeval) (err error) {
if len(tv) != 2 { if len(tv) != 2 {
return EINVAL return EINVAL
} }
h, e := CreateFile(StringToUTF16Ptr(path), pathp, e := UTF16PtrFromString(path)
if e != nil {
return e
}
h, e := CreateFile(pathp,
FILE_WRITE_ATTRIBUTES, FILE_SHARE_WRITE, nil, FILE_WRITE_ATTRIBUTES, FILE_SHARE_WRITE, nil,
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0) OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0)
if e != nil { if e != nil {
...@@ -423,7 +484,10 @@ func Chmod(path string, mode uint32) (err error) { ...@@ -423,7 +484,10 @@ func Chmod(path string, mode uint32) (err error) {
if mode == 0 { if mode == 0 {
return EINVAL return EINVAL
} }
p := StringToUTF16Ptr(path) p, e := UTF16PtrFromString(path)
if e != nil {
return e
}
attrs, e := GetFileAttributes(p) attrs, e := GetFileAttributes(p)
if e != nil { if e != nil {
return e return e
......
...@@ -35,7 +35,8 @@ func TestWin32finddata(t *testing.T) { ...@@ -35,7 +35,8 @@ func TestWin32finddata(t *testing.T) {
var want byte = 2 // it is unlikely to have this character in the filename var want byte = 2 // it is unlikely to have this character in the filename
x := X{got: want} x := X{got: want}
h, err := syscall.FindFirstFile(syscall.StringToUTF16Ptr(path), &(x.fd)) pathp, _ := syscall.UTF16PtrFromString(path)
h, err := syscall.FindFirstFile(pathp, &(x.fd))
if err != nil { if err != nil {
t.Fatalf("FindFirstFile failed: %v", err) t.Fatalf("FindFirstFile failed: %v", err)
} }
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
...@@ -7,13 +7,6 @@ import "unsafe" ...@@ -7,13 +7,6 @@ import "unsafe"
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func exits(msg *byte) {
Syscall(SYS_EXITS, uintptr(unsafe.Pointer(msg)), 0, 0)
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func fd2path(fd int, buf []byte) (err error) { func fd2path(fd int, buf []byte) (err error) {
var _p0 unsafe.Pointer var _p0 unsafe.Pointer
if len(buf) > 0 { if len(buf) > 0 {
...@@ -69,7 +62,12 @@ func Dup(oldfd int, newfd int) (fd int, err error) { ...@@ -69,7 +62,12 @@ func Dup(oldfd int, newfd int) (fd int, err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func Open(path string, mode int) (fd int, err error) { func Open(path string, mode int) (fd int, err error) {
r0, _, e1 := Syscall(SYS_OPEN, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode), 0) var _p0 *byte
_p0, err = BytePtrFromString(path)
if err != nil {
return
}
r0, _, e1 := Syscall(SYS_OPEN, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
fd = int(r0) fd = int(r0)
if int(r0) == -1 { if int(r0) == -1 {
err = e1 err = e1
...@@ -80,7 +78,12 @@ func Open(path string, mode int) (fd int, err error) { ...@@ -80,7 +78,12 @@ func Open(path string, mode int) (fd int, err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func Create(path string, mode int, perm uint32) (fd int, err error) { func Create(path string, mode int, perm uint32) (fd int, err error) {
r0, _, e1 := Syscall(SYS_CREATE, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode), uintptr(perm)) var _p0 *byte
_p0, err = BytePtrFromString(path)
if err != nil {
return
}
r0, _, e1 := Syscall(SYS_CREATE, uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(perm))
fd = int(r0) fd = int(r0)
if int(r0) == -1 { if int(r0) == -1 {
err = e1 err = e1
...@@ -91,7 +94,12 @@ func Create(path string, mode int, perm uint32) (fd int, err error) { ...@@ -91,7 +94,12 @@ func Create(path string, mode int, perm uint32) (fd int, err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func Remove(path string) (err error) { func Remove(path string) (err error) {
r0, _, e1 := Syscall(SYS_REMOVE, uintptr(unsafe.Pointer(StringBytePtr(path))), 0, 0) var _p0 *byte
_p0, err = BytePtrFromString(path)
if err != nil {
return
}
r0, _, e1 := Syscall(SYS_REMOVE, uintptr(unsafe.Pointer(_p0)), 0, 0)
if int(r0) == -1 { if int(r0) == -1 {
err = e1 err = e1
} }
...@@ -145,7 +153,12 @@ func Close(fd int) (err error) { ...@@ -145,7 +153,12 @@ func Close(fd int) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func Chdir(path string) (err error) { func Chdir(path string) (err error) {
r0, _, e1 := Syscall(SYS_CHDIR, uintptr(unsafe.Pointer(StringBytePtr(path))), 0, 0) var _p0 *byte
_p0, err = BytePtrFromString(path)
if err != nil {
return
}
r0, _, e1 := Syscall(SYS_CHDIR, uintptr(unsafe.Pointer(_p0)), 0, 0)
if int(r0) == -1 { if int(r0) == -1 {
err = e1 err = e1
} }
...@@ -155,7 +168,17 @@ func Chdir(path string) (err error) { ...@@ -155,7 +168,17 @@ func Chdir(path string) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func Bind(name string, old string, flag int) (err error) { func Bind(name string, old string, flag int) (err error) {
r0, _, e1 := Syscall(SYS_BIND, uintptr(unsafe.Pointer(StringBytePtr(name))), uintptr(unsafe.Pointer(StringBytePtr(old))), uintptr(flag)) var _p0 *byte
_p0, err = BytePtrFromString(name)
if err != nil {
return
}
var _p1 *byte
_p1, err = BytePtrFromString(old)
if err != nil {
return
}
r0, _, e1 := Syscall(SYS_BIND, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(flag))
if int(r0) == -1 { if int(r0) == -1 {
err = e1 err = e1
} }
...@@ -165,7 +188,17 @@ func Bind(name string, old string, flag int) (err error) { ...@@ -165,7 +188,17 @@ func Bind(name string, old string, flag int) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func Mount(fd int, afd int, old string, flag int, aname string) (err error) { func Mount(fd int, afd int, old string, flag int, aname string) (err error) {
r0, _, e1 := Syscall6(SYS_MOUNT, uintptr(fd), uintptr(afd), uintptr(unsafe.Pointer(StringBytePtr(old))), uintptr(flag), uintptr(unsafe.Pointer(StringBytePtr(aname))), 0) var _p0 *byte
_p0, err = BytePtrFromString(old)
if err != nil {
return
}
var _p1 *byte
_p1, err = BytePtrFromString(aname)
if err != nil {
return
}
r0, _, e1 := Syscall6(SYS_MOUNT, uintptr(fd), uintptr(afd), uintptr(unsafe.Pointer(_p0)), uintptr(flag), uintptr(unsafe.Pointer(_p1)), 0)
if int(r0) == -1 { if int(r0) == -1 {
err = e1 err = e1
} }
...@@ -175,13 +208,18 @@ func Mount(fd int, afd int, old string, flag int, aname string) (err error) { ...@@ -175,13 +208,18 @@ func Mount(fd int, afd int, old string, flag int, aname string) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func Stat(path string, edir []byte) (n int, err error) { func Stat(path string, edir []byte) (n int, err error) {
var _p0 unsafe.Pointer var _p0 *byte
_p0, err = BytePtrFromString(path)
if err != nil {
return
}
var _p1 unsafe.Pointer
if len(edir) > 0 { if len(edir) > 0 {
_p0 = unsafe.Pointer(&edir[0]) _p1 = unsafe.Pointer(&edir[0])
} else { } else {
_p0 = unsafe.Pointer(&_zero) _p1 = unsafe.Pointer(&_zero)
} }
r0, _, e1 := Syscall(SYS_STAT, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(_p0), uintptr(len(edir))) r0, _, e1 := Syscall(SYS_STAT, uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(edir)))
n = int(r0) n = int(r0)
if int(r0) == -1 { if int(r0) == -1 {
err = e1 err = e1
...@@ -209,13 +247,18 @@ func Fstat(fd int, edir []byte) (n int, err error) { ...@@ -209,13 +247,18 @@ func Fstat(fd int, edir []byte) (n int, err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func Wstat(path string, edir []byte) (err error) { func Wstat(path string, edir []byte) (err error) {
var _p0 unsafe.Pointer var _p0 *byte
_p0, err = BytePtrFromString(path)
if err != nil {
return
}
var _p1 unsafe.Pointer
if len(edir) > 0 { if len(edir) > 0 {
_p0 = unsafe.Pointer(&edir[0]) _p1 = unsafe.Pointer(&edir[0])
} else { } else {
_p0 = unsafe.Pointer(&_zero) _p1 = unsafe.Pointer(&_zero)
} }
r0, _, e1 := Syscall(SYS_WSTAT, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(_p0), uintptr(len(edir))) r0, _, e1 := Syscall(SYS_WSTAT, uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(edir)))
if int(r0) == -1 { if int(r0) == -1 {
err = e1 err = e1
} }
......
...@@ -155,7 +155,12 @@ func GetLastError() (lasterr error) { ...@@ -155,7 +155,12 @@ func GetLastError() (lasterr error) {
} }
func LoadLibrary(libname string) (handle Handle, err error) { func LoadLibrary(libname string) (handle Handle, err error) {
r0, _, e1 := Syscall(procLoadLibraryW.Addr(), 1, uintptr(unsafe.Pointer(StringToUTF16Ptr(libname))), 0, 0) var _p0 *uint16
_p0, err = UTF16PtrFromString(libname)
if err != nil {
return
}
r0, _, e1 := Syscall(procLoadLibraryW.Addr(), 1, uintptr(unsafe.Pointer(_p0)), 0, 0)
handle = Handle(r0) handle = Handle(r0)
if handle == 0 { if handle == 0 {
if e1 != 0 { if e1 != 0 {
...@@ -180,7 +185,12 @@ func FreeLibrary(handle Handle) (err error) { ...@@ -180,7 +185,12 @@ func FreeLibrary(handle Handle) (err error) {
} }
func GetProcAddress(module Handle, procname string) (proc uintptr, err error) { func GetProcAddress(module Handle, procname string) (proc uintptr, err error) {
r0, _, e1 := Syscall(procGetProcAddress.Addr(), 2, uintptr(module), uintptr(unsafe.Pointer(StringBytePtr(procname))), 0) var _p0 *byte
_p0, err = BytePtrFromString(procname)
if err != nil {
return
}
r0, _, e1 := Syscall(procGetProcAddress.Addr(), 2, uintptr(module), uintptr(unsafe.Pointer(_p0)), 0)
proc = uintptr(r0) proc = uintptr(r0)
if proc == 0 { if proc == 0 {
if e1 != 0 { if e1 != 0 {
...@@ -1406,7 +1416,12 @@ func WSASendTo(s Handle, bufs *WSABuf, bufcnt uint32, sent *uint32, flags uint32 ...@@ -1406,7 +1416,12 @@ func WSASendTo(s Handle, bufs *WSABuf, bufcnt uint32, sent *uint32, flags uint32
} }
func GetHostByName(name string) (h *Hostent, err error) { func GetHostByName(name string) (h *Hostent, err error) {
r0, _, e1 := Syscall(procgethostbyname.Addr(), 1, uintptr(unsafe.Pointer(StringBytePtr(name))), 0, 0) var _p0 *byte
_p0, err = BytePtrFromString(name)
if err != nil {
return
}
r0, _, e1 := Syscall(procgethostbyname.Addr(), 1, uintptr(unsafe.Pointer(_p0)), 0, 0)
h = (*Hostent)(unsafe.Pointer(r0)) h = (*Hostent)(unsafe.Pointer(r0))
if h == nil { if h == nil {
if e1 != 0 { if e1 != 0 {
...@@ -1419,7 +1434,17 @@ func GetHostByName(name string) (h *Hostent, err error) { ...@@ -1419,7 +1434,17 @@ func GetHostByName(name string) (h *Hostent, err error) {
} }
func GetServByName(name string, proto string) (s *Servent, err error) { func GetServByName(name string, proto string) (s *Servent, err error) {
r0, _, e1 := Syscall(procgetservbyname.Addr(), 2, uintptr(unsafe.Pointer(StringBytePtr(name))), uintptr(unsafe.Pointer(StringBytePtr(proto))), 0) var _p0 *byte
_p0, err = BytePtrFromString(name)
if err != nil {
return
}
var _p1 *byte
_p1, err = BytePtrFromString(proto)
if err != nil {
return
}
r0, _, e1 := Syscall(procgetservbyname.Addr(), 2, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0)
s = (*Servent)(unsafe.Pointer(r0)) s = (*Servent)(unsafe.Pointer(r0))
if s == nil { if s == nil {
if e1 != 0 { if e1 != 0 {
...@@ -1438,7 +1463,12 @@ func Ntohs(netshort uint16) (u uint16) { ...@@ -1438,7 +1463,12 @@ func Ntohs(netshort uint16) (u uint16) {
} }
func GetProtoByName(name string) (p *Protoent, err error) { func GetProtoByName(name string) (p *Protoent, err error) {
r0, _, e1 := Syscall(procgetprotobyname.Addr(), 1, uintptr(unsafe.Pointer(StringBytePtr(name))), 0, 0) var _p0 *byte
_p0, err = BytePtrFromString(name)
if err != nil {
return
}
r0, _, e1 := Syscall(procgetprotobyname.Addr(), 1, uintptr(unsafe.Pointer(_p0)), 0, 0)
p = (*Protoent)(unsafe.Pointer(r0)) p = (*Protoent)(unsafe.Pointer(r0))
if p == nil { if p == nil {
if e1 != 0 { if e1 != 0 {
...@@ -1451,7 +1481,12 @@ func GetProtoByName(name string) (p *Protoent, err error) { ...@@ -1451,7 +1481,12 @@ func GetProtoByName(name string) (p *Protoent, err error) {
} }
func DnsQuery(name string, qtype uint16, options uint32, extra *byte, qrs **DNSRecord, pr *byte) (status error) { func DnsQuery(name string, qtype uint16, options uint32, extra *byte, qrs **DNSRecord, pr *byte) (status error) {
r0, _, _ := Syscall6(procDnsQuery_W.Addr(), 6, uintptr(unsafe.Pointer(StringToUTF16Ptr(name))), uintptr(qtype), uintptr(options), uintptr(unsafe.Pointer(extra)), uintptr(unsafe.Pointer(qrs)), uintptr(unsafe.Pointer(pr))) var _p0 *uint16
_p0, status = UTF16PtrFromString(name)
if status != nil {
return
}
r0, _, _ := Syscall6(procDnsQuery_W.Addr(), 6, uintptr(unsafe.Pointer(_p0)), uintptr(qtype), uintptr(options), uintptr(unsafe.Pointer(extra)), uintptr(unsafe.Pointer(qrs)), uintptr(unsafe.Pointer(pr)))
if r0 != 0 { if r0 != 0 {
status = Errno(r0) status = Errno(r0)
} }
......
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment