summaryrefslogtreecommitdiff
path: root/libgo/go/os
diff options
context:
space:
mode:
authorian <ian@138bc75d-0d04-0410-961f-82ee72b054a4>2012-02-09 08:19:58 +0000
committerian <ian@138bc75d-0d04-0410-961f-82ee72b054a4>2012-02-09 08:19:58 +0000
commit2da6f72bb78de6e6ca3d387d970cb21bf36684be (patch)
tree7ca86535c5a6b99d4cc432ba5cfddabc5ee4ea16 /libgo/go/os
parent98ea39f2b59cc0a4a0a32b095e8f0faa84fd7882 (diff)
downloadgcc-2da6f72bb78de6e6ca3d387d970cb21bf36684be.tar.gz
libgo: Update to weekly.2012-02-07.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@184034 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'libgo/go/os')
-rw-r--r--libgo/go/os/exec.go4
-rw-r--r--libgo/go/os/exec/exec_test.go24
-rw-r--r--libgo/go/os/exec_posix.go2
-rw-r--r--libgo/go/os/exec_windows.go11
-rw-r--r--libgo/go/os/file_unix.go2
-rw-r--r--libgo/go/os/getwd.go8
-rw-r--r--libgo/go/os/os_test.go8
-rw-r--r--libgo/go/os/os_unix_test.go4
-rw-r--r--libgo/go/os/signal/signal.go37
-rw-r--r--libgo/go/os/signal/signal_test.go22
-rw-r--r--libgo/go/os/stat.go14
-rw-r--r--libgo/go/os/stat_openbsd.go14
-rw-r--r--libgo/go/os/stat_plan9.go12
-rw-r--r--libgo/go/os/types.go34
-rw-r--r--libgo/go/os/user/lookup_stubs.go12
-rw-r--r--libgo/go/os/user/lookup_unix.go18
-rw-r--r--libgo/go/os/user/lookup_windows.go117
-rw-r--r--libgo/go/os/user/user.go10
-rw-r--r--libgo/go/os/user/user_test.go74
19 files changed, 284 insertions, 143 deletions
diff --git a/libgo/go/os/exec.go b/libgo/go/os/exec.go
index 33e223fd296..6e0f168c767 100644
--- a/libgo/go/os/exec.go
+++ b/libgo/go/os/exec.go
@@ -12,11 +12,11 @@ import (
// Process stores the information about a process created by StartProcess.
type Process struct {
Pid int
- handle int
+ handle uintptr
done bool // process has been successfuly waited on
}
-func newProcess(pid, handle int) *Process {
+func newProcess(pid int, handle uintptr) *Process {
p := &Process{Pid: pid, handle: handle}
runtime.SetFinalizer(p, (*Process).Release)
return p
diff --git a/libgo/go/os/exec/exec_test.go b/libgo/go/os/exec/exec_test.go
index 11cfe79c724..d00d12008f7 100644
--- a/libgo/go/os/exec/exec_test.go
+++ b/libgo/go/os/exec/exec_test.go
@@ -17,6 +17,7 @@ import (
"runtime"
"strconv"
"strings"
+ "syscall"
"testing"
)
@@ -150,6 +151,15 @@ func TestExtraFiles(t *testing.T) {
return
}
+ // Ensure that file descriptors have not already been leaked into
+ // our environment.
+ for fd := os.Stderr.Fd() + 1; fd <= 101; fd++ {
+ err := syscall.Close(fd)
+ if err == nil {
+ t.Logf("Something already leaked - closed fd %d", fd)
+ }
+ }
+
// Force network usage, to verify the epoll (or whatever) fd
// doesn't leak to the child,
ln, err := net.Listen("tcp", "127.0.0.1:0")
@@ -202,6 +212,13 @@ func TestHelperProcess(*testing.T) {
}
defer os.Exit(0)
+ // Determine which command to use to display open files.
+ ofcmd := "lsof"
+ switch runtime.GOOS {
+ case "freebsd", "netbsd", "openbsd":
+ ofcmd = "fstat"
+ }
+
args := os.Args
for len(args) > 0 {
if args[0] == "--" {
@@ -282,7 +299,7 @@ func TestHelperProcess(*testing.T) {
}
if got := f.Fd(); got != wantfd {
fmt.Printf("leaked parent file. fd = %d; want %d\n", got, wantfd)
- out, _ := Command("lsof", "-p", fmt.Sprint(os.Getpid())).CombinedOutput()
+ out, _ := Command(ofcmd, "-p", fmt.Sprint(os.Getpid())).CombinedOutput()
fmt.Print(string(out))
os.Exit(1)
}
@@ -292,6 +309,11 @@ func TestHelperProcess(*testing.T) {
f.Close()
}
}
+ // Referring to fd3 here ensures that it is not
+ // garbage collected, and therefore closed, while
+ // executing the wantfd loop above. It doesn't matter
+ // what we do with fd3 as long as we refer to it;
+ // closing it is the easy choice.
fd3.Close()
os.Stderr.Write(bs)
case "exit":
diff --git a/libgo/go/os/exec_posix.go b/libgo/go/os/exec_posix.go
index 218b8cdc1d6..6465bfbb653 100644
--- a/libgo/go/os/exec_posix.go
+++ b/libgo/go/os/exec_posix.go
@@ -48,7 +48,7 @@ func StartProcess(name string, argv []string, attr *ProcAttr) (p *Process, err e
// Kill causes the Process to exit immediately.
func (p *Process) Kill() error {
- return p.Signal(SIGKILL)
+ return p.Signal(UnixSignal(syscall.SIGKILL))
}
// Exec replaces the current process with an execution of the
diff --git a/libgo/go/os/exec_windows.go b/libgo/go/os/exec_windows.go
index 7eb7d194d60..9463d2c0e3f 100644
--- a/libgo/go/os/exec_windows.go
+++ b/libgo/go/os/exec_windows.go
@@ -29,7 +29,7 @@ func (p *Process) Wait(options int) (w *Waitmsg, err error) {
return nil, NewSyscallError("GetExitCodeProcess", e)
}
p.done = true
- return &Waitmsg{p.Pid, syscall.WaitStatus{s, ec}, new(syscall.Rusage)}, nil
+ return &Waitmsg{p.Pid, syscall.WaitStatus{Status: s, ExitCode: ec}, new(syscall.Rusage)}, nil
}
// Signal sends a signal to the Process.
@@ -37,8 +37,7 @@ func (p *Process) Signal(sig Signal) error {
if p.done {
return errors.New("os: process already finished")
}
- switch sig.(UnixSignal) {
- case SIGKILL:
+ if us, ok := sig.(UnixSignal); ok && us == syscall.SIGKILL {
e := syscall.TerminateProcess(syscall.Handle(p.handle), 1)
return NewSyscallError("TerminateProcess", e)
}
@@ -47,14 +46,14 @@ func (p *Process) Signal(sig Signal) error {
// Release releases any resources associated with the Process.
func (p *Process) Release() error {
- if p.handle == -1 {
+ if p.handle == uintptr(syscall.InvalidHandle) {
return EINVAL
}
e := syscall.CloseHandle(syscall.Handle(p.handle))
if e != nil {
return NewSyscallError("CloseHandle", e)
}
- p.handle = -1
+ p.handle = uintptr(syscall.InvalidHandle)
// no need for a finalizer anymore
runtime.SetFinalizer(p, nil)
return nil
@@ -67,7 +66,7 @@ func findProcess(pid int) (p *Process, err error) {
if e != nil {
return nil, NewSyscallError("OpenProcess", e)
}
- return newProcess(pid, int(h)), nil
+ return newProcess(pid, uintptr(h)), nil
}
func init() {
diff --git a/libgo/go/os/file_unix.go b/libgo/go/os/file_unix.go
index 9a9ed92ee3c..8c61a82248f 100644
--- a/libgo/go/os/file_unix.go
+++ b/libgo/go/os/file_unix.go
@@ -158,7 +158,7 @@ func (f *File) readdir(n int) (fi []FileInfo, err error) {
if err == nil {
fi[i] = fip
} else {
- fi[i] = &FileStat{name: filename}
+ fi[i] = &fileStat{name: filename}
}
}
return fi, err
diff --git a/libgo/go/os/getwd.go b/libgo/go/os/getwd.go
index a0d3c99a503..56836434dbe 100644
--- a/libgo/go/os/getwd.go
+++ b/libgo/go/os/getwd.go
@@ -30,7 +30,7 @@ func Getwd() (pwd string, err error) {
pwd = Getenv("PWD")
if len(pwd) > 0 && pwd[0] == '/' {
d, err := Stat(pwd)
- if err == nil && dot.(*FileStat).SameFile(d.(*FileStat)) {
+ if err == nil && SameFile(dot, d) {
return pwd, nil
}
}
@@ -42,7 +42,7 @@ func Getwd() (pwd string, err error) {
// Can't stat root - no hope.
return "", err
}
- if root.(*FileStat).SameFile(dot.(*FileStat)) {
+ if SameFile(root, dot) {
return "/", nil
}
@@ -67,7 +67,7 @@ func Getwd() (pwd string, err error) {
}
for _, name := range names {
d, _ := Lstat(parent + "/" + name)
- if d.(*FileStat).SameFile(dot.(*FileStat)) {
+ if SameFile(d, dot) {
pwd = "/" + name + pwd
goto Found
}
@@ -82,7 +82,7 @@ func Getwd() (pwd string, err error) {
return "", err
}
fd.Close()
- if pd.(*FileStat).SameFile(root.(*FileStat)) {
+ if SameFile(pd, root) {
break
}
// Set up for next round.
diff --git a/libgo/go/os/os_test.go b/libgo/go/os/os_test.go
index 59f2bb06150..36bb496d979 100644
--- a/libgo/go/os/os_test.go
+++ b/libgo/go/os/os_test.go
@@ -406,7 +406,7 @@ func TestHardLink(t *testing.T) {
if err != nil {
t.Fatalf("stat %q failed: %v", from, err)
}
- if !tostat.(*FileStat).SameFile(fromstat.(*FileStat)) {
+ if !SameFile(tostat, fromstat) {
t.Errorf("link %q, %q did not create hard link", to, from)
}
}
@@ -442,7 +442,7 @@ func TestSymLink(t *testing.T) {
if err != nil {
t.Fatalf("stat %q failed: %v", from, err)
}
- if !tostat.(*FileStat).SameFile(fromstat.(*FileStat)) {
+ if !SameFile(tostat, fromstat) {
t.Errorf("symlink %q, %q did not create symlink", to, from)
}
fromstat, err = Lstat(from)
@@ -656,7 +656,7 @@ func TestChtimes(t *testing.T) {
if err != nil {
t.Fatalf("Stat %s: %s", f.Name(), err)
}
- preStat := st.(*FileStat)
+ preStat := st
// Move access and modification time back a second
at := Atime(preStat)
@@ -670,7 +670,7 @@ func TestChtimes(t *testing.T) {
if err != nil {
t.Fatalf("second Stat %s: %s", f.Name(), err)
}
- postStat := st.(*FileStat)
+ postStat := st
/* Plan 9:
Mtime is the time of the last change of content. Similarly, atime is set whenever the
diff --git a/libgo/go/os/os_unix_test.go b/libgo/go/os/os_unix_test.go
index 1bdcd748bc0..f8e330beba4 100644
--- a/libgo/go/os/os_unix_test.go
+++ b/libgo/go/os/os_unix_test.go
@@ -18,7 +18,7 @@ func checkUidGid(t *testing.T, path string, uid, gid int) {
if err != nil {
t.Fatalf("Stat %q (looking for uid/gid %d/%d): %s", path, uid, gid, err)
}
- sys := dir.(*FileStat).Sys.(*syscall.Stat_t)
+ sys := dir.Sys().(*syscall.Stat_t)
if int(sys.Uid) != uid {
t.Errorf("Stat %q: uid %d want %d", path, sys.Uid, uid)
}
@@ -52,7 +52,7 @@ func TestChown(t *testing.T) {
if err = Chown(f.Name(), -1, gid); err != nil {
t.Fatalf("chown %s -1 %d: %s", f.Name(), gid, err)
}
- sys := dir.(*FileStat).Sys.(*syscall.Stat_t)
+ sys := dir.Sys().(*syscall.Stat_t)
checkUidGid(t, f.Name(), int(sys.Uid), gid)
// Then try all the auxiliary groups.
diff --git a/libgo/go/os/signal/signal.go b/libgo/go/os/signal/signal.go
deleted file mode 100644
index bce4530e7bc..00000000000
--- a/libgo/go/os/signal/signal.go
+++ /dev/null
@@ -1,37 +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.
-
-// +build darwin freebsd linux netbsd openbsd
-
-// Package signal implements operating system-independent signal handling.
-package signal
-
-import (
- "os"
- "runtime"
-)
-
-// Incoming is the global signal channel.
-// All signals received by the program will be delivered to this channel.
-var Incoming <-chan os.Signal
-
-func process(ch chan<- os.Signal) {
- for {
- var mask uint32 = runtime.Sigrecv()
- for sig := uint(0); sig < 32; sig++ {
- if mask&(1<<sig) != 0 {
- ch <- os.UnixSignal(sig)
- }
- }
- }
-}
-
-func init() {
- runtime.Siginit()
- ch := make(chan os.Signal) // Done here so Incoming can have type <-chan Signal
- Incoming = ch
- go process(ch)
-}
-
-// BUG(rsc): This package is unavailable on Plan 9 and Windows.
diff --git a/libgo/go/os/signal/signal_test.go b/libgo/go/os/signal/signal_test.go
deleted file mode 100644
index 4568aa9518e..00000000000
--- a/libgo/go/os/signal/signal_test.go
+++ /dev/null
@@ -1,22 +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.
-
-// +build darwin freebsd linux netbsd openbsd
-
-package signal
-
-import (
- "os"
- "syscall"
- "testing"
-)
-
-func TestSignal(t *testing.T) {
- // Send this process a SIGHUP.
- syscall.Syscall(syscall.SYS_KILL, uintptr(syscall.Getpid()), syscall.SIGHUP, 0)
-
- if sig := (<-Incoming).(os.UnixSignal); sig != os.SIGHUP {
- t.Errorf("signal was %v, want %v", sig, os.SIGHUP)
- }
-}
diff --git a/libgo/go/os/stat.go b/libgo/go/os/stat.go
index c664fc189b8..789007206fa 100644
--- a/libgo/go/os/stat.go
+++ b/libgo/go/os/stat.go
@@ -9,18 +9,18 @@ import (
"time"
)
-func sameFile(fs1, fs2 *FileStat) bool {
- sys1 := fs1.Sys.(*syscall.Stat_t)
- sys2 := fs2.Sys.(*syscall.Stat_t)
- return sys1.Dev == sys2.Dev && sys1.Ino == sys2.Ino
+func sameFile(sys1, sys2 interface{}) bool {
+ stat1 := sys1.(*syscall.Stat_t)
+ stat2 := sys2.(*syscall.Stat_t)
+ return stat1.Dev == stat2.Dev && stat1.Ino == stat2.Ino
}
func fileInfoFromStat(st *syscall.Stat_t, name string) FileInfo {
- fs := &FileStat{
+ fs := &fileStat{
name: basename(name),
size: int64(st.Size),
modTime: timespecToTime(st.Mtime),
- Sys: st,
+ sys: st,
}
fs.mode = FileMode(st.Mode & 0777)
switch st.Mode & syscall.S_IFMT {
@@ -52,5 +52,5 @@ func timespecToTime(ts syscall.Timespec) time.Time {
// For testing.
func atime(fi FileInfo) time.Time {
- return timespecToTime(fi.(*FileStat).Sys.(*syscall.Stat_t).Atime)
+ return timespecToTime(fi.Sys().(*syscall.Stat_t).Atime)
}
diff --git a/libgo/go/os/stat_openbsd.go b/libgo/go/os/stat_openbsd.go
index 8d1323af9c6..00506b2b609 100644
--- a/libgo/go/os/stat_openbsd.go
+++ b/libgo/go/os/stat_openbsd.go
@@ -9,18 +9,18 @@ import (
"time"
)
-func sameFile(fs1, fs2 *FileStat) bool {
- sys1 := fs1.Sys.(*syscall.Stat_t)
- sys2 := fs2.Sys.(*syscall.Stat_t)
- return sys1.Dev == sys2.Dev && sys1.Ino == sys2.Ino
+func sameFile(sys1, sys2 interface{}) bool {
+ stat1 := sys1.(*syscall.Stat_t)
+ stat2 := sys2.(*syscall.Stat_t)
+ return stat1.Dev == stat2.Dev && stat1.Ino == stat2.Ino
}
func fileInfoFromStat(st *syscall.Stat_t, name string) FileInfo {
- fs := &FileStat{
+ fs := &fileStat{
name: basename(name),
size: int64(st.Size),
modTime: timespecToTime(st.Mtim),
- Sys: st,
+ sys: st,
}
fs.mode = FileMode(st.Mode & 0777)
switch st.Mode & syscall.S_IFMT {
@@ -57,5 +57,5 @@ func timespecToTime(ts syscall.Timespec) time.Time {
// For testing.
func atime(fi FileInfo) time.Time {
- return timespecToTime(fi.(*FileStat).Sys.(*syscall.Stat_t).Atim)
+ return timespecToTime(fi.Sys().(*syscall.Stat_t).Atim)
}
diff --git a/libgo/go/os/stat_plan9.go b/libgo/go/os/stat_plan9.go
index f731e43740a..7c2d1bd4efc 100644
--- a/libgo/go/os/stat_plan9.go
+++ b/libgo/go/os/stat_plan9.go
@@ -9,18 +9,18 @@ import (
"time"
)
-func sameFile(fs1, fs2 *FileStat) bool {
- a := fs1.Sys.(*Dir)
- b := fs2.Sys.(*Dir)
+func sameFile(sys1, sys2 interface{}) bool {
+ a := sys1.(*Dir)
+ b := sys2.(*Dir)
return a.Qid.Path == b.Qid.Path && a.Type == b.Type && a.Dev == b.Dev
}
func fileInfoFromStat(d *Dir) FileInfo {
- fs := &FileStat{
+ fs := &fileStat{
name: d.Name,
size: int64(d.Length),
modTime: time.Unix(int64(d.Mtime), 0),
- Sys: d,
+ sys: d,
}
fs.mode = FileMode(d.Mode & 0777)
if d.Mode&syscall.DMDIR != 0 {
@@ -100,5 +100,5 @@ func Lstat(name string) (FileInfo, error) {
// For testing.
func atime(fi FileInfo) time.Time {
- return time.Unix(int64(fi.(*FileStat).Sys.(*Dir).Atime), 0)
+ return time.Unix(int64(fi.Sys().(*Dir).Atime), 0)
}
diff --git a/libgo/go/os/types.go b/libgo/go/os/types.go
index a3f187c25cb..c7c5199be1c 100644
--- a/libgo/go/os/types.go
+++ b/libgo/go/os/types.go
@@ -19,6 +19,7 @@ type FileInfo interface {
Mode() FileMode // file mode bits
ModTime() time.Time // modification time
IsDir() bool // abbreviation for Mode().IsDir()
+ Sys() interface{} // underlying data source (can return nil)
}
// A FileMode represents a file's mode and permission bits.
@@ -92,28 +93,33 @@ func (m FileMode) Perm() FileMode {
return m & ModePerm
}
-// A FileStat is the implementation of FileInfo returned by Stat and Lstat.
-// Clients that need access to the underlying system-specific stat information
-// can test for *os.FileStat and then consult the Sys field.
-type FileStat struct {
+// A fileStat is the implementation of FileInfo returned by Stat and Lstat.
+type fileStat struct {
name string
size int64
mode FileMode
modTime time.Time
-
- Sys interface{}
+ sys interface{}
}
-func (fs *FileStat) Name() string { return fs.name }
-func (fs *FileStat) Size() int64 { return fs.size }
-func (fs *FileStat) Mode() FileMode { return fs.mode }
-func (fs *FileStat) ModTime() time.Time { return fs.modTime }
-func (fs *FileStat) IsDir() bool { return fs.mode.IsDir() }
+func (fs *fileStat) Name() string { return fs.name }
+func (fs *fileStat) Size() int64 { return fs.size }
+func (fs *fileStat) Mode() FileMode { return fs.mode }
+func (fs *fileStat) ModTime() time.Time { return fs.modTime }
+func (fs *fileStat) IsDir() bool { return fs.mode.IsDir() }
+func (fs *fileStat) Sys() interface{} { return fs.sys }
-// SameFile reports whether fs and other describe the same file.
+// SameFile reports whether fi1 and fi2 describe the same file.
// For example, on Unix this means that the device and inode fields
// of the two underlying structures are identical; on other systems
// the decision may be based on the path names.
-func (fs *FileStat) SameFile(other *FileStat) bool {
- return sameFile(fs, other)
+// SameFile only applies to results returned by this package's Stat.
+// It returns false in other cases.
+func SameFile(fi1, fi2 FileInfo) bool {
+ fs1, ok1 := fi1.(*fileStat)
+ fs2, ok2 := fi2.(*fileStat)
+ if !ok1 || !ok2 {
+ return false
+ }
+ return sameFile(fs1.sys, fs2.sys)
}
diff --git a/libgo/go/os/user/lookup_stubs.go b/libgo/go/os/user/lookup_stubs.go
index 10f5170a9c9..415f869f229 100644
--- a/libgo/go/os/user/lookup_stubs.go
+++ b/libgo/go/os/user/lookup_stubs.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build !cgo windows
+// +build !cgo,!windows
package user
@@ -11,10 +11,18 @@ import (
"runtime"
)
+func init() {
+ implemented = false
+}
+
+func Current() (*User, error) {
+ return nil, fmt.Errorf("user: Current not implemented on %s/%s", runtime.GOOS, runtime.GOARCH)
+}
+
func Lookup(username string) (*User, error) {
return nil, fmt.Errorf("user: Lookup not implemented on %s/%s", runtime.GOOS, runtime.GOARCH)
}
-func LookupId(int) (*User, error) {
+func LookupId(string) (*User, error) {
return nil, fmt.Errorf("user: LookupId not implemented on %s/%s", runtime.GOOS, runtime.GOARCH)
}
diff --git a/libgo/go/os/user/lookup_unix.go b/libgo/go/os/user/lookup_unix.go
index 8939cebfcd8..68f8914d089 100644
--- a/libgo/go/os/user/lookup_unix.go
+++ b/libgo/go/os/user/lookup_unix.go
@@ -9,6 +9,7 @@ package user
import (
"fmt"
+ "strconv"
"strings"
"syscall"
"unsafe"
@@ -43,8 +44,9 @@ func bytePtrToString(p *byte) string {
return string(a[:i])
}
-func init() {
- implemented = true
+// Current returns the current user.
+func Current() (*User, error) {
+ return lookup(syscall.Getuid(), "", false)
}
// Lookup looks up a user by username. If the user cannot be found,
@@ -55,8 +57,12 @@ func Lookup(username string) (*User, error) {
// LookupId looks up a user by userid. If the user cannot be found,
// the returned error is of type UnknownUserIdError.
-func LookupId(uid int) (*User, error) {
- return lookup(uid, "", false)
+func LookupId(uid string) (*User, error) {
+ i, e := strconv.Atoi(uid)
+ if e != nil {
+ return nil, e
+ }
+ return lookup(i, "", false)
}
func lookup(uid int, username string, lookupByName bool) (*User, error) {
@@ -92,8 +98,8 @@ func lookup(uid int, username string, lookupByName bool) (*User, error) {
}
}
u := &User{
- Uid: int(pwd.Pw_uid),
- Gid: int(pwd.Pw_gid),
+ Uid: strconv.Itoa(int(pwd.Pw_uid)),
+ Gid: strconv.Itoa(int(pwd.Pw_gid)),
Username: bytePtrToString((*byte)(unsafe.Pointer(pwd.Pw_name))),
Name: bytePtrToString((*byte)(unsafe.Pointer(pwd.Pw_gecos))),
HomeDir: bytePtrToString((*byte)(unsafe.Pointer(pwd.Pw_dir))),
diff --git a/libgo/go/os/user/lookup_windows.go b/libgo/go/os/user/lookup_windows.go
new file mode 100644
index 00000000000..99368711594
--- /dev/null
+++ b/libgo/go/os/user/lookup_windows.go
@@ -0,0 +1,117 @@
+// 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 user
+
+import (
+ "fmt"
+ "syscall"
+ "unsafe"
+)
+
+func lookupFullName(domain, username, domainAndUser string) (string, error) {
+ // try domain controller first
+ name, e := syscall.TranslateAccountName(domainAndUser,
+ syscall.NameSamCompatible, syscall.NameDisplay, 50)
+ if e != nil {
+ // domain lookup failed, perhaps this pc is not part of domain
+ d := syscall.StringToUTF16Ptr(domain)
+ u := syscall.StringToUTF16Ptr(username)
+ var p *byte
+ e := syscall.NetUserGetInfo(d, u, 10, &p)
+ if e != nil {
+ return "", e
+ }
+ defer syscall.NetApiBufferFree(p)
+ i := (*syscall.UserInfo10)(unsafe.Pointer(p))
+ if i.FullName == nil {
+ return "", nil
+ }
+ name = syscall.UTF16ToString((*[1024]uint16)(unsafe.Pointer(i.FullName))[:])
+ }
+ return name, nil
+}
+
+func newUser(usid *syscall.SID, gid, dir string) (*User, error) {
+ username, domain, t, e := usid.LookupAccount("")
+ if e != nil {
+ return nil, e
+ }
+ if t != syscall.SidTypeUser {
+ return nil, fmt.Errorf("user: should be user account type, not %d", t)
+ }
+ domainAndUser := domain + `\` + username
+ uid, e := usid.String()
+ if e != nil {
+ return nil, e
+ }
+ name, e := lookupFullName(domain, username, domainAndUser)
+ if e != nil {
+ return nil, e
+ }
+ u := &User{
+ Uid: uid,
+ Gid: gid,
+ Username: domainAndUser,
+ Name: name,
+ HomeDir: dir,
+ }
+ return u, nil
+}
+
+// Current returns the current user.
+func Current() (*User, error) {
+ t, e := syscall.OpenCurrentProcessToken()
+ if e != nil {
+ return nil, e
+ }
+ u, e := t.GetTokenUser()
+ if e != nil {
+ return nil, e
+ }
+ pg, e := t.GetTokenPrimaryGroup()
+ if e != nil {
+ return nil, e
+ }
+ gid, e := pg.PrimaryGroup.String()
+ if e != nil {
+ return nil, e
+ }
+ dir, e := t.GetUserProfileDirectory()
+ if e != nil {
+ return nil, e
+ }
+ return newUser(u.User.Sid, gid, dir)
+}
+
+// BUG(brainman): Lookup and LookupId functions do not set
+// Gid and HomeDir fields in the User struct returned on windows.
+
+func newUserFromSid(usid *syscall.SID) (*User, error) {
+ // TODO(brainman): do not know where to get gid and dir fields
+ gid := "unknown"
+ dir := "Unknown directory"
+ return newUser(usid, gid, dir)
+}
+
+// Lookup looks up a user by username.
+func Lookup(username string) (*User, error) {
+ sid, _, t, e := syscall.LookupSID("", username)
+ if e != nil {
+ return nil, e
+ }
+ if t != syscall.SidTypeUser {
+ return nil, fmt.Errorf("user: should be user account type, not %d", t)
+ }
+ return newUserFromSid(sid)
+}
+
+// LookupId looks up a user by userid.
+func LookupId(uid string) (*User, error) {
+ sid, e := syscall.StringToSid(uid)
+ if e != nil {
+ return nil, e
+ }
+ return newUserFromSid(sid)
+}
diff --git a/libgo/go/os/user/user.go b/libgo/go/os/user/user.go
index a0195377765..841f2263f95 100644
--- a/libgo/go/os/user/user.go
+++ b/libgo/go/os/user/user.go
@@ -9,12 +9,16 @@ import (
"strconv"
)
-var implemented = false // set to true by lookup_unix.go's init
+var implemented = true // set to false by lookup_stubs.go's init
// User represents a user account.
+//
+// On posix systems Uid and Gid contain a decimal number
+// representing uid and gid. On windows Uid and Gid
+// contain security identifier (SID) in a string format.
type User struct {
- Uid int // user id
- Gid int // primary group id
+ Uid string // user id
+ Gid string // primary group id
Username string
Name string
HomeDir string
diff --git a/libgo/go/os/user/user_test.go b/libgo/go/os/user/user_test.go
index f9f44af8a93..b812ebce79a 100644
--- a/libgo/go/os/user/user_test.go
+++ b/libgo/go/os/user/user_test.go
@@ -6,9 +6,7 @@ package user
import (
"os"
- "reflect"
"runtime"
- "syscall"
"testing"
)
@@ -18,7 +16,8 @@ func skip(t *testing.T) bool {
return true
}
- if runtime.GOOS == "linux" || runtime.GOOS == "freebsd" || runtime.GOOS == "darwin" {
+ switch runtime.GOOS {
+ case "linux", "freebsd", "darwin", "windows":
return false
}
@@ -26,36 +25,75 @@ func skip(t *testing.T) bool {
return true
}
-func TestLookup(t *testing.T) {
+func TestCurrent(t *testing.T) {
if skip(t) {
return
}
- // Test LookupId on the current user
- uid := syscall.Getuid()
- u, err := LookupId(uid)
+ u, err := Current()
if err != nil {
- t.Fatalf("LookupId: %v", err)
- }
- if e, g := uid, u.Uid; e != g {
- t.Errorf("expected Uid of %d; got %d", e, g)
+ t.Fatalf("Current: %v", err)
}
fi, err := os.Stat(u.HomeDir)
if err != nil || !fi.IsDir() {
- t.Errorf("expected a valid HomeDir; stat(%q): err=%v, IsDir=%v", u.HomeDir, err, fi.IsDir())
+ t.Errorf("expected a valid HomeDir; stat(%q): err=%v", u.HomeDir, err)
}
if u.Username == "" {
t.Fatalf("didn't get a username")
}
+}
+
+func compare(t *testing.T, want, got *User) {
+ if want.Uid != got.Uid {
+ t.Errorf("got Uid=%q; want %q", got.Uid, want.Uid)
+ }
+ if want.Username != got.Username {
+ t.Errorf("got Username=%q; want %q", got.Username, want.Username)
+ }
+ if want.Name != got.Name {
+ t.Errorf("got Name=%q; want %q", got.Name, want.Name)
+ }
+ // TODO(brainman): fix it once we know how.
+ if runtime.GOOS == "windows" {
+ t.Log("skipping Gid and HomeDir comparisons")
+ return
+ }
+ if want.Gid != got.Gid {
+ t.Errorf("got Gid=%q; want %q", got.Gid, want.Gid)
+ }
+ if want.HomeDir != got.HomeDir {
+ t.Errorf("got HomeDir=%q; want %q", got.HomeDir, want.HomeDir)
+ }
+}
+
+func TestLookup(t *testing.T) {
+ if skip(t) {
+ return
+ }
- // Test Lookup by username, using the username from LookupId
- un, err := Lookup(u.Username)
+ want, err := Current()
+ if err != nil {
+ t.Fatalf("Current: %v", err)
+ }
+ got, err := Lookup(want.Username)
if err != nil {
t.Fatalf("Lookup: %v", err)
}
- if !reflect.DeepEqual(u, un) {
- t.Errorf("Lookup by userid vs. name didn't match\n"+
- "LookupId(%d): %#v\n"+
- "Lookup(%q): %#v\n", uid, u, u.Username, un)
+ compare(t, want, got)
+}
+
+func TestLookupId(t *testing.T) {
+ if skip(t) {
+ return
+ }
+
+ want, err := Current()
+ if err != nil {
+ t.Fatalf("Current: %v", err)
+ }
+ got, err := LookupId(want.Uid)
+ if err != nil {
+ t.Fatalf("LookupId: %v", err)
}
+ compare(t, want, got)
}