diff options
author | ian <ian@138bc75d-0d04-0410-961f-82ee72b054a4> | 2012-02-09 08:19:58 +0000 |
---|---|---|
committer | ian <ian@138bc75d-0d04-0410-961f-82ee72b054a4> | 2012-02-09 08:19:58 +0000 |
commit | 2da6f72bb78de6e6ca3d387d970cb21bf36684be (patch) | |
tree | 7ca86535c5a6b99d4cc432ba5cfddabc5ee4ea16 /libgo/go/os | |
parent | 98ea39f2b59cc0a4a0a32b095e8f0faa84fd7882 (diff) | |
download | gcc-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.go | 4 | ||||
-rw-r--r-- | libgo/go/os/exec/exec_test.go | 24 | ||||
-rw-r--r-- | libgo/go/os/exec_posix.go | 2 | ||||
-rw-r--r-- | libgo/go/os/exec_windows.go | 11 | ||||
-rw-r--r-- | libgo/go/os/file_unix.go | 2 | ||||
-rw-r--r-- | libgo/go/os/getwd.go | 8 | ||||
-rw-r--r-- | libgo/go/os/os_test.go | 8 | ||||
-rw-r--r-- | libgo/go/os/os_unix_test.go | 4 | ||||
-rw-r--r-- | libgo/go/os/signal/signal.go | 37 | ||||
-rw-r--r-- | libgo/go/os/signal/signal_test.go | 22 | ||||
-rw-r--r-- | libgo/go/os/stat.go | 14 | ||||
-rw-r--r-- | libgo/go/os/stat_openbsd.go | 14 | ||||
-rw-r--r-- | libgo/go/os/stat_plan9.go | 12 | ||||
-rw-r--r-- | libgo/go/os/types.go | 34 | ||||
-rw-r--r-- | libgo/go/os/user/lookup_stubs.go | 12 | ||||
-rw-r--r-- | libgo/go/os/user/lookup_unix.go | 18 | ||||
-rw-r--r-- | libgo/go/os/user/lookup_windows.go | 117 | ||||
-rw-r--r-- | libgo/go/os/user/user.go | 10 | ||||
-rw-r--r-- | libgo/go/os/user/user_test.go | 74 |
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) } |