diff options
Diffstat (limited to 'src/pkg/os')
-rw-r--r-- | src/pkg/os/Makefile | 17 | ||||
-rw-r--r-- | src/pkg/os/dir_plan9.go | 82 | ||||
-rw-r--r-- | src/pkg/os/dir_unix.go | 45 | ||||
-rw-r--r-- | src/pkg/os/dir_windows.go | 9 | ||||
-rw-r--r-- | src/pkg/os/env.go | 2 | ||||
-rw-r--r-- | src/pkg/os/env_plan9.go | 15 | ||||
-rw-r--r-- | src/pkg/os/env_unix.go | 30 | ||||
-rw-r--r-- | src/pkg/os/error_posix.go | 2 | ||||
-rw-r--r-- | src/pkg/os/exec_posix.go | 25 | ||||
-rw-r--r-- | src/pkg/os/exec_unix.go | 8 | ||||
-rw-r--r-- | src/pkg/os/exec_windows.go | 12 | ||||
-rw-r--r-- | src/pkg/os/file_unix.go | 24 | ||||
-rw-r--r-- | src/pkg/os/file_windows.go | 38 | ||||
-rwxr-xr-x | src/pkg/os/mkunixsignals.sh (renamed from src/pkg/os/signal/mkunix.sh) | 2 | ||||
-rw-r--r-- | src/pkg/os/os_test.go | 92 | ||||
-rw-r--r-- | src/pkg/os/path.go | 9 | ||||
-rw-r--r-- | src/pkg/os/path_plan9.go | 15 | ||||
-rw-r--r-- | src/pkg/os/path_test.go | 20 | ||||
-rw-r--r-- | src/pkg/os/path_unix.go | 15 | ||||
-rw-r--r-- | src/pkg/os/path_windows.go | 16 | ||||
-rw-r--r-- | src/pkg/os/signal/Makefile | 6 | ||||
-rw-r--r-- | src/pkg/os/signal/signal.go | 25 | ||||
-rw-r--r-- | src/pkg/os/signal/signal_test.go | 5 | ||||
-rw-r--r-- | src/pkg/os/user/user_test.go | 4 |
24 files changed, 385 insertions, 133 deletions
diff --git a/src/pkg/os/Makefile b/src/pkg/os/Makefile index cd9284079..497e5a958 100644 --- a/src/pkg/os/Makefile +++ b/src/pkg/os/Makefile @@ -23,9 +23,11 @@ GOFILES_freebsd=\ env_unix.go\ file_posix.go\ file_unix.go\ + path_unix.go\ sys_bsd.go\ exec_posix.go\ exec_unix.go\ + signal_unix.go\ GOFILES_darwin=\ dir_unix.go\ @@ -33,9 +35,11 @@ GOFILES_darwin=\ env_unix.go\ file_posix.go\ file_unix.go\ + path_unix.go\ sys_bsd.go\ exec_posix.go\ exec_unix.go\ + signal_unix.go\ GOFILES_linux=\ dir_unix.go\ @@ -43,9 +47,11 @@ GOFILES_linux=\ env_unix.go\ file_posix.go\ file_unix.go\ + path_unix.go\ sys_linux.go\ exec_posix.go\ exec_unix.go\ + signal_unix.go\ GOFILES_windows=\ dir_windows.go\ @@ -53,18 +59,29 @@ GOFILES_windows=\ env_windows.go\ file_posix.go\ file_windows.go\ + path_windows.go\ sys_windows.go\ exec_posix.go\ exec_windows.go\ + signal_windows.go\ GOFILES_plan9=\ dir_plan9.go\ error_plan9.go\ env_plan9.go\ file_plan9.go\ + path_plan9.go\ sys_plan9.go\ exec_plan9.go\ GOFILES+=$(GOFILES_$(GOOS)) +CLEANFILES+=signal_unix.go signal_windows.go + include ../../Make.pkg + +signal_unix.go: ../syscall/zerrors_$(GOOS)_$(GOARCH).go + ./mkunixsignals.sh $< > $@ || rm -f $@ + +signal_windows.go: ../syscall/ztypes_$(GOOS)_$(GOARCH).go + ./mkunixsignals.sh $< > $@ || rm -f $@ diff --git a/src/pkg/os/dir_plan9.go b/src/pkg/os/dir_plan9.go index d9514191d..bbc2cb647 100644 --- a/src/pkg/os/dir_plan9.go +++ b/src/pkg/os/dir_plan9.go @@ -9,35 +9,46 @@ import ( ) // Readdir reads the contents of the directory associated with file and -// returns an array of up to count FileInfo structures, in directory order. -// Subsequent calls on the same file will yield further FileInfos. -// A negative count means to read until EOF. -// Readdir returns the array and an Error, if any. -func (file *File) Readdir(count int) (fi []FileInfo, err Error) { +// returns an array of up to n FileInfo structures, as would be returned +// by Lstat, in directory order. Subsequent calls on the same file will yield +// further FileInfos. +// +// If n > 0, Readdir returns at most n FileInfo structures. In this case, if +// Readdirnames returns an empty slice, it will return a non-nil error +// explaining why. At the end of a directory, the error is os.EOF. +// +// If n <= 0, Readdir returns all the FileInfo from the directory in +// a single slice. In this case, if Readdir succeeds (reads all +// the way to the end of the directory), it returns the slice and a +// nil os.Error. If it encounters an error before the end of the +// directory, Readdir returns the FileInfo read until that point +// and a non-nil error. +func (file *File) Readdir(n int) (fi []FileInfo, err Error) { // If this file has no dirinfo, create one. if file.dirinfo == nil { file.dirinfo = new(dirInfo) } d := file.dirinfo - size := count - if size < 0 { + size := n + if size <= 0 { size = 100 + n = -1 } result := make([]FileInfo, 0, size) // Empty with room to grow. - for count != 0 { + for n != 0 { // Refill the buffer if necessary if d.bufp >= d.nbuf { d.bufp = 0 var e Error d.nbuf, e = file.Read(d.buf[:]) if e != nil && e != EOF { - return nil, &PathError{"readdir", file.name, e} + return result, &PathError{"readdir", file.name, e} } if e == EOF { break } if d.nbuf < syscall.STATFIXLEN { - return nil, &PathError{"readdir", file.name, Eshortstat} + return result, &PathError{"readdir", file.name, Eshortstat} } } @@ -45,39 +56,44 @@ func (file *File) Readdir(count int) (fi []FileInfo, err Error) { m, _ := gbit16(d.buf[d.bufp:]) m += 2 if m < syscall.STATFIXLEN { - return nil, &PathError{"readdir", file.name, Eshortstat} + return result, &PathError{"readdir", file.name, Eshortstat} } dir, e := UnmarshalDir(d.buf[d.bufp : d.bufp+int(m)]) if e != nil { - return nil, &PathError{"readdir", file.name, e} + return result, &PathError{"readdir", file.name, e} } var f FileInfo fileInfoFromStat(&f, dir) result = append(result, f) d.bufp += int(m) - count-- + n-- } - return result, nil -} -// Readdirnames returns an array of up to count file names residing in the -// directory associated with file. A negative count will return all of them. -// Readdir returns the array and an Error, if any. -func (file *File) Readdirnames(count int) (names []string, err Error) { - fi, e := file.Readdir(count) - - if e != nil { - return []string{}, e + if n >= 0 && len(result) == 0 { + return result, EOF } + return result, nil +} +// Readdirnames reads and returns a slice of names from the directory f. +// +// If n > 0, Readdirnames returns at most n names. In this case, if +// Readdirnames returns an empty slice, it will return a non-nil error +// explaining why. At the end of a directory, the error is os.EOF. +// +// If n <= 0, Readdirnames returns all the names from the directory in +// a single slice. In this case, if Readdirnames succeeds (reads all +// the way to the end of the directory), it returns the slice and a +// nil os.Error. If it encounters an error before the end of the +// directory, Readdirnames returns the names read until that point and +// a non-nil error. +func (file *File) Readdirnames(n int) (names []string, err Error) { + fi, err := file.Readdir(n) names = make([]string, len(fi)) - err = nil - for i := range fi { names[i] = fi[i].Name } - return } @@ -142,7 +158,7 @@ func pdir(b []byte, d *Dir) []byte { return b } -// UnmarshalDir reads a 9P Stat message from a 9P protocol message strored in b, +// UnmarshalDir reads a 9P Stat message from a 9P protocol message stored in b, // returning the corresponding Dir struct. func UnmarshalDir(b []byte) (d *Dir, err Error) { n := uint16(0) @@ -172,7 +188,7 @@ func UnmarshalDir(b []byte) (d *Dir, err Error) { return d, nil } -// gqid reads the qid part of a 9P Stat message from a 9P protocol message strored in b, +// gqid reads the qid part of a 9P Stat message from a 9P protocol message stored in b, // returning the corresponding Qid struct and the remaining slice of b. func gqid(b []byte) (Qid, []byte) { var q Qid @@ -190,25 +206,25 @@ func pqid(b []byte, q Qid) []byte { return b } -// gbit8 reads a byte-sized numeric value from a 9P protocol message strored in b, +// gbit8 reads a byte-sized numeric value from a 9P protocol message stored in b, // returning the value and the remaining slice of b. func gbit8(b []byte) (uint8, []byte) { return uint8(b[0]), b[1:] } -// gbit16 reads a 16-bit numeric value from a 9P protocol message strored 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. func gbit16(b []byte) (uint16, []byte) { return uint16(b[0]) | uint16(b[1])<<8, b[2:] } -// gbit32 reads a 32-bit numeric value from a 9P protocol message strored in b, +// gbit32 reads a 32-bit numeric value from a 9P protocol message stored in b, // returning the value and the remaining slice of b. func gbit32(b []byte) (uint32, []byte) { return uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24, b[4:] } -// gbit64 reads a 64-bit numeric value from a 9P protocol message strored in b, +// gbit64 reads a 64-bit numeric value from a 9P protocol message stored in b, // returning the value and the remaining slice of b. func gbit64(b []byte) (uint64, []byte) { lo, b := gbit32(b) @@ -216,7 +232,7 @@ func gbit64(b []byte) (uint64, []byte) { return uint64(hi)<<32 | uint64(lo), b } -// gstring reads a string from a 9P protocol message strored in b, +// gstring reads a string from a 9P protocol message stored in b, // returning the value as a Go string and the remaining slice of b. func gstring(b []byte) (string, []byte) { n, b := gbit16(b) diff --git a/src/pkg/os/dir_unix.go b/src/pkg/os/dir_unix.go index f5b82230d..7835ed52b 100644 --- a/src/pkg/os/dir_unix.go +++ b/src/pkg/os/dir_unix.go @@ -12,30 +12,40 @@ const ( blockSize = 4096 ) -// Readdirnames reads the contents of the directory associated with file and -// returns an array of up to count names, in directory order. Subsequent -// calls on the same file will yield further names. -// A negative count means to read until EOF. -// Readdirnames returns the array and an Error, if any. -func (file *File) Readdirnames(count int) (names []string, err Error) { +// Readdirnames reads and returns a slice of names from the directory f. +// +// If n > 0, Readdirnames returns at most n names. In this case, if +// Readdirnames returns an empty slice, it will return a non-nil error +// explaining why. At the end of a directory, the error is os.EOF. +// +// If n <= 0, Readdirnames returns all the names from the directory in +// a single slice. In this case, if Readdirnames succeeds (reads all +// the way to the end of the directory), it returns the slice and a +// nil os.Error. If it encounters an error before the end of the +// directory, Readdirnames returns the names read until that point and +// a non-nil error. +func (f *File) Readdirnames(n int) (names []string, err Error) { // If this file has no dirinfo, create one. - if file.dirinfo == nil { - file.dirinfo = new(dirInfo) + if f.dirinfo == nil { + f.dirinfo = new(dirInfo) // The buffer must be at least a block long. - file.dirinfo.buf = make([]byte, blockSize) + f.dirinfo.buf = make([]byte, blockSize) } - d := file.dirinfo - size := count - if size < 0 { + d := f.dirinfo + + size := n + if size <= 0 { size = 100 + n = -1 } + names = make([]string, 0, size) // Empty with room to grow. - for count != 0 { + for n != 0 { // Refill the buffer if necessary if d.bufp >= d.nbuf { d.bufp = 0 var errno int - d.nbuf, errno = syscall.ReadDirent(file.fd, d.buf) + d.nbuf, errno = syscall.ReadDirent(f.fd, d.buf) if errno != 0 { return names, NewSyscallError("readdirent", errno) } @@ -46,9 +56,12 @@ func (file *File) Readdirnames(count int) (names []string, err Error) { // Drain the buffer var nb, nc int - nb, nc, names = syscall.ParseDirent(d.buf[d.bufp:d.nbuf], count, names) + nb, nc, names = syscall.ParseDirent(d.buf[d.bufp:d.nbuf], n, names) d.bufp += nb - count -= nc + n -= nc + } + if n >= 0 && len(names) == 0 { + return names, EOF } return names, nil } diff --git a/src/pkg/os/dir_windows.go b/src/pkg/os/dir_windows.go index 0d8267b59..d76e88fdb 100644 --- a/src/pkg/os/dir_windows.go +++ b/src/pkg/os/dir_windows.go @@ -4,14 +4,11 @@ package os -func (file *File) Readdirnames(count int) (names []string, err Error) { - fis, e := file.Readdir(count) - if e != nil { - return nil, e - } +func (file *File) Readdirnames(n int) (names []string, err Error) { + fis, err := file.Readdir(n) names = make([]string, len(fis)) for i, fi := range fis { names[i] = fi.Name } - return names, nil + return names, err } diff --git a/src/pkg/os/env.go b/src/pkg/os/env.go index 3a6d79dd0..3772c090b 100644 --- a/src/pkg/os/env.go +++ b/src/pkg/os/env.go @@ -6,6 +6,8 @@ package os +func setenv_c(k, v string) + // Expand replaces ${var} or $var in the string based on the mapping function. // Invocations of undefined variables are replaced with the empty string. func Expand(s string, mapping func(string) string) string { diff --git a/src/pkg/os/env_plan9.go b/src/pkg/os/env_plan9.go index 14df55ed0..1fed89f92 100644 --- a/src/pkg/os/env_plan9.go +++ b/src/pkg/os/env_plan9.go @@ -23,13 +23,18 @@ func Getenverror(key string) (value string, err Error) { } defer f.Close() - var buf [4096]byte - n, e := f.Read(buf[:len(buf)-1]) + l, _ := f.Seek(0, 2) + f.Seek(0, 0) + buf := make([]byte, l) + n, e := f.Read(buf) if iserror(e) { return "", ENOENV } - buf[n] = 0 - return string(buf[0:n]), nil + + if n > 0 && buf[n-1] == 0 { + buf = buf[:n-1] + } + return string(buf), nil } // Getenv retrieves the value of the environment variable named by the key. @@ -52,7 +57,7 @@ func Setenv(key, value string) Error { } defer f.Close() - _, e = f.Write(syscall.StringByteSlice(value)) + _, e = f.Write([]byte(value)) return nil } diff --git a/src/pkg/os/env_unix.go b/src/pkg/os/env_unix.go index e7e1c3b90..8aa71e83a 100644 --- a/src/pkg/os/env_unix.go +++ b/src/pkg/os/env_unix.go @@ -29,6 +29,8 @@ func copyenv() { } } +var envLock sync.RWMutex + // Getenverror retrieves the value of the environment variable named by the key. // It returns the value and an error, if any. func Getenverror(key string) (value string, err Error) { @@ -37,6 +39,10 @@ func Getenverror(key string) (value string, err Error) { if len(key) == 0 { return "", EINVAL } + + envLock.RLock() + defer envLock.RUnlock() + v, ok := env[key] if !ok { return "", ENOENV @@ -55,35 +61,43 @@ func Getenv(key string) string { // It returns an Error, if any. func Setenv(key, value string) Error { once.Do(copyenv) - if len(key) == 0 { return EINVAL } + + envLock.Lock() + defer envLock.Unlock() + env[key] = value + setenv_c(key, value) // is a no-op if cgo isn't loaded return nil } // Clearenv deletes all environment variables. func Clearenv() { once.Do(copyenv) // prevent copyenv in Getenv/Setenv + + envLock.Lock() + defer envLock.Unlock() + env = make(map[string]string) + + // TODO(bradfitz): pass through to C } // Environ returns an array of strings representing the environment, // in the form "key=value". func Environ() []string { once.Do(copyenv) + envLock.RLock() + defer envLock.RUnlock() a := make([]string, len(env)) i := 0 for k, v := range env { - // check i < len(a) for safety, - // in case env is changing underfoot. - if i < len(a) { - a[i] = k + "=" + v - i++ - } + a[i] = k + "=" + v + i++ } - return a[0:i] + return a } // TempDir returns the default directory to use for temporary files. diff --git a/src/pkg/os/error_posix.go b/src/pkg/os/error_posix.go index 0ee34e4b0..d43f1786d 100644 --- a/src/pkg/os/error_posix.go +++ b/src/pkg/os/error_posix.go @@ -13,7 +13,7 @@ type Errno int64 func (e Errno) String() string { return syscall.Errstr(int(e)) } func (e Errno) Temporary() bool { - return e == Errno(syscall.EINTR) || e.Timeout() + return e == Errno(syscall.EINTR) || e == Errno(syscall.EMFILE) || e.Timeout() } func (e Errno) Timeout() bool { diff --git a/src/pkg/os/exec_posix.go b/src/pkg/os/exec_posix.go index 9102dc0a4..bf992ef42 100644 --- a/src/pkg/os/exec_posix.go +++ b/src/pkg/os/exec_posix.go @@ -4,7 +4,25 @@ package os -import "syscall" +import ( + "runtime" + "syscall" +) + +// A Signal can represent any operating system signal. +type Signal interface { + String() string +} + +type UnixSignal int32 + +func (sig UnixSignal) String() string { + s := runtime.Signame(int32(sig)) + if len(s) > 0 { + return s + } + return "UnixSignal" +} // StartProcess starts a new process with the program, arguments and attributes // specified by name, argv and attr. @@ -34,6 +52,11 @@ func StartProcess(name string, argv []string, attr *ProcAttr) (p *Process, err E return newProcess(pid, h), nil } +// Kill causes the Process to exit immediately. +func (p *Process) Kill() Error { + return p.Signal(SIGKILL) +} + // Exec replaces the current process with an execution of the // named binary, with arguments argv and environment envv. // If successful, Exec never returns. If it fails, it returns an Error. diff --git a/src/pkg/os/exec_unix.go b/src/pkg/os/exec_unix.go index 8990d6a97..cf5ea9b61 100644 --- a/src/pkg/os/exec_unix.go +++ b/src/pkg/os/exec_unix.go @@ -45,6 +45,14 @@ func (p *Process) Wait(options int) (w *Waitmsg, err Error) { return w, nil } +// Signal sends a signal to the Process. +func (p *Process) Signal(sig Signal) Error { + if e := syscall.Kill(p.Pid, int(sig.(UnixSignal))); e != 0 { + return Errno(e) + } + return nil +} + // Release releases any resources associated with the Process. func (p *Process) Release() Error { // NOOP for unix. diff --git a/src/pkg/os/exec_windows.go b/src/pkg/os/exec_windows.go index ae8ffeab2..bac33b908 100644 --- a/src/pkg/os/exec_windows.go +++ b/src/pkg/os/exec_windows.go @@ -20,13 +20,23 @@ func (p *Process) Wait(options int) (w *Waitmsg, err Error) { return nil, ErrorString("os: unexpected result from WaitForSingleObject") } var ec uint32 - e = syscall.GetExitCodeProcess(uint32(p.handle), &ec) + e = syscall.GetExitCodeProcess(int32(p.handle), &ec) if e != 0 { return nil, NewSyscallError("GetExitCodeProcess", e) } return &Waitmsg{p.Pid, syscall.WaitStatus{s, ec}, new(syscall.Rusage)}, nil } +// Signal sends a signal to the Process. +func (p *Process) Signal(sig Signal) Error { + switch sig.(UnixSignal) { + case SIGKILL: + e := syscall.TerminateProcess(int32(p.handle), 1) + return NewSyscallError("TerminateProcess", e) + } + return Errno(syscall.EWINDOWS) +} + func (p *Process) Release() Error { if p.handle == -1 { return EINVAL diff --git a/src/pkg/os/file_unix.go b/src/pkg/os/file_unix.go index 2fb28df65..def9b3bf0 100644 --- a/src/pkg/os/file_unix.go +++ b/src/pkg/os/file_unix.go @@ -69,21 +69,27 @@ func (file *File) Stat() (fi *FileInfo, err Error) { } // Readdir reads the contents of the directory associated with file and -// returns an array of up to count FileInfo structures, as would be returned -// by Lstat, in directory order. Subsequent calls on the same file will yield +// returns an array of up to n FileInfo structures, as would be returned +// by Lstat, in directory order. Subsequent calls on the same file will yield // further FileInfos. -// A negative count means to read until EOF. -// Readdir returns the array and an Error, if any. -func (file *File) Readdir(count int) (fi []FileInfo, err Error) { +// +// If n > 0, Readdir returns at most n FileInfo structures. In this case, if +// Readdir returns an empty slice, it will return a non-nil error +// explaining why. At the end of a directory, the error is os.EOF. +// +// If n <= 0, Readdir returns all the FileInfo from the directory in +// a single slice. In this case, if Readdir succeeds (reads all +// the way to the end of the directory), it returns the slice and a +// nil os.Error. If it encounters an error before the end of the +// directory, Readdir returns the FileInfo read until that point +// and a non-nil error. +func (file *File) Readdir(n int) (fi []FileInfo, err Error) { dirname := file.name if dirname == "" { dirname = "." } dirname += "/" - names, err1 := file.Readdirnames(count) - if err1 != nil { - return nil, err1 - } + names, err := file.Readdirnames(n) fi = make([]FileInfo, len(names)) for i, filename := range names { fip, err := Lstat(dirname + filename) diff --git a/src/pkg/os/file_windows.go b/src/pkg/os/file_windows.go index 95f60b735..80886f6f5 100644 --- a/src/pkg/os/file_windows.go +++ b/src/pkg/os/file_windows.go @@ -123,12 +123,21 @@ func (file *File) Stat() (fi *FileInfo, err Error) { } // Readdir reads the contents of the directory associated with file and -// returns an array of up to count FileInfo structures, as would be returned -// by Lstat, in directory order. Subsequent calls on the same file will yield +// returns an array of up to n FileInfo structures, as would be returned +// by Lstat, in directory order. Subsequent calls on the same file will yield // further FileInfos. -// A negative count means to read until EOF. -// Readdir returns the array and an Error, if any. -func (file *File) Readdir(count int) (fi []FileInfo, err Error) { +// +// If n > 0, Readdir returns at most n FileInfo structures. In this case, if +// Readdir returns an empty slice, it will return a non-nil error +// explaining why. At the end of a directory, the error is os.EOF. +// +// If n <= 0, Readdir returns all the FileInfo from the directory in +// a single slice. In this case, if Readdir succeeds (reads all +// the way to the end of the directory), it returns the slice and a +// nil os.Error. If it encounters an error before the end of the +// directory, Readdir returns the FileInfo read until that point +// and a non-nil error. +func (file *File) Readdir(n int) (fi []FileInfo, err Error) { if file == nil || file.fd < 0 { return nil, EINVAL } @@ -136,12 +145,14 @@ func (file *File) Readdir(count int) (fi []FileInfo, err Error) { return nil, &PathError{"Readdir", file.name, ENOTDIR} } di := file.dirinfo - size := count - if size < 0 { + wantAll := n <= 0 + size := n + if wantAll { + n = -1 size = 100 } fi = make([]FileInfo, 0, size) // Empty with room to grow. - for count != 0 { + for n != 0 { if di.usefirststat { di.usefirststat = false } else { @@ -150,7 +161,11 @@ func (file *File) Readdir(count int) (fi []FileInfo, err Error) { if e == syscall.ERROR_NO_MORE_FILES { break } else { - return nil, &PathError{"FindNextFile", file.name, Errno(e)} + err = &PathError{"FindNextFile", file.name, Errno(e)} + if !wantAll { + fi = nil + } + return } } } @@ -159,9 +174,12 @@ func (file *File) Readdir(count int) (fi []FileInfo, err Error) { if f.Name == "." || f.Name == ".." { // Useless names continue } - count-- + n-- fi = append(fi, f) } + if !wantAll && len(fi) == 0 { + return fi, EOF + } return fi, nil } diff --git a/src/pkg/os/signal/mkunix.sh b/src/pkg/os/mkunixsignals.sh index 653b01664..6ec764cbd 100755 --- a/src/pkg/os/signal/mkunix.sh +++ b/src/pkg/os/mkunixsignals.sh @@ -8,7 +8,7 @@ echo '// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT' echo cat <<EOH -package signal +package os import ( "syscall" diff --git a/src/pkg/os/os_test.go b/src/pkg/os/os_test.go index 65475c118..8eabdee6b 100644 --- a/src/pkg/os/os_test.go +++ b/src/pkg/os/os_test.go @@ -236,11 +236,14 @@ func smallReaddirnames(file *File, length int, t *testing.T) []string { count := 0 for { d, err := file.Readdirnames(1) + if err == EOF { + break + } if err != nil { - t.Fatalf("readdir %q failed: %v", file.Name(), err) + t.Fatalf("readdirnames %q failed: %v", file.Name(), err) } if len(d) == 0 { - break + t.Fatalf("readdirnames %q returned empty slice and no error", file.Name()) } names[count] = d[0] count++ @@ -283,6 +286,78 @@ func TestReaddirnamesOneAtATime(t *testing.T) { } } +func TestReaddirNValues(t *testing.T) { + if testing.Short() { + t.Logf("test.short; skipping") + return + } + dir, err := ioutil.TempDir("", "") + if err != nil { + t.Fatalf("TempDir: %v", err) + } + defer RemoveAll(dir) + for i := 1; i <= 105; i++ { + f, err := Create(filepath.Join(dir, fmt.Sprintf("%d", i))) + if err != nil { + t.Fatalf("Create: %v", err) + } + f.Write([]byte(strings.Repeat("X", i))) + f.Close() + } + + var d *File + openDir := func() { + var err Error + d, err = Open(dir) + if err != nil { + t.Fatalf("Open directory: %v", err) + } + } + + readDirExpect := func(n, want int, wantErr Error) { + fi, err := d.Readdir(n) + if err != wantErr { + t.Fatalf("Readdir of %d got error %v, want %v", n, err, wantErr) + } + if g, e := len(fi), want; g != e { + t.Errorf("Readdir of %d got %d files, want %d", n, g, e) + } + } + + readDirNamesExpect := func(n, want int, wantErr Error) { + fi, err := d.Readdirnames(n) + if err != wantErr { + t.Fatalf("Readdirnames of %d got error %v, want %v", n, err, wantErr) + } + if g, e := len(fi), want; g != e { + t.Errorf("Readdirnames of %d got %d files, want %d", n, g, e) + } + } + + for _, fn := range []func(int, int, Error){readDirExpect, readDirNamesExpect} { + // Test the slurp case + openDir() + fn(0, 105, nil) + fn(0, 0, nil) + d.Close() + + // Slurp with -1 instead + openDir() + fn(-1, 105, nil) + fn(-2, 0, nil) + fn(0, 0, nil) + d.Close() + + // Test the bounded case + openDir() + fn(1, 1, nil) + fn(2, 2, nil) + fn(105, 102, nil) // and tests buffer >100 case + fn(3, 0, EOF) + d.Close() + } +} + func TestHardLink(t *testing.T) { // Hardlinks are not supported under windows. if syscall.OS == "windows" { @@ -439,7 +514,8 @@ func exec(t *testing.T, dir, cmd string, args []string, expect string) { var b bytes.Buffer io.Copy(&b, r) output := b.String() - if output != expect { + // Accept /usr prefix because Solaris /bin is symlinked to /usr/bin. + if output != expect && output != "/usr"+expect { t.Errorf("exec %q returned %q wanted %q", strings.Join(append([]string{cmd}, args...), " "), output, expect) } @@ -914,7 +990,15 @@ func TestAppend(t *testing.T) { } s = writeFile(t, f, O_CREATE|O_APPEND|O_RDWR, "new&append") if s != "new&append" { - t.Fatalf("writeFile: have %q want %q", s, "new&append") + t.Fatalf("writeFile: after append have %q want %q", s, "new&append") + } + s = writeFile(t, f, O_CREATE|O_RDWR, "old") + if s != "old&append" { + t.Fatalf("writeFile: after create have %q want %q", s, "old&append") + } + s = writeFile(t, f, O_CREATE|O_TRUNC|O_RDWR, "new") + if s != "new" { + t.Fatalf("writeFile: after truncate have %q want %q", s, "new") } } diff --git a/src/pkg/os/path.go b/src/pkg/os/path.go index 0eb3ee503..7b93036aa 100644 --- a/src/pkg/os/path.go +++ b/src/pkg/os/path.go @@ -24,12 +24,12 @@ func MkdirAll(path string, perm uint32) Error { // Doesn't already exist; make sure parent does. i := len(path) - for i > 0 && path[i-1] == '/' { // Skip trailing slashes. + for i > 0 && IsPathSeparator(path[i-1]) { // Skip trailing path separator. i-- } j := i - for j > 0 && path[j-1] != '/' { // Scan backward over element. + for j > 0 && !IsPathSeparator(path[j-1]) { // Scan backward over element. j-- } @@ -90,11 +90,14 @@ func RemoveAll(path string) Error { for { names, err1 := fd.Readdirnames(100) for _, name := range names { - err1 := RemoveAll(path + "/" + name) + err1 := RemoveAll(path + string(PathSeparator) + name) if err == nil { err = err1 } } + if err1 == EOF { + break + } // If Readdirnames returned an error, use it. if err == nil { err = err1 diff --git a/src/pkg/os/path_plan9.go b/src/pkg/os/path_plan9.go new file mode 100644 index 000000000..3121b7bc7 --- /dev/null +++ b/src/pkg/os/path_plan9.go @@ -0,0 +1,15 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package os + +const ( + PathSeparator = '/' // OS-specific path separator + PathListSeparator = 0 // OS-specific path list separator +) + +// IsPathSeparator returns true if c is a directory separator character. +func IsPathSeparator(c uint8) bool { + return PathSeparator == c +} diff --git a/src/pkg/os/path_test.go b/src/pkg/os/path_test.go index 483bb6395..d58945aab 100644 --- a/src/pkg/os/path_test.go +++ b/src/pkg/os/path_test.go @@ -6,6 +6,7 @@ package os_test import ( . "os" + "path/filepath" "testing" "runtime" "syscall" @@ -29,10 +30,11 @@ func TestMkdirAll(t *testing.T) { // Make file. fpath := path + "/file" - _, err = Create(fpath) + f, err := Create(fpath) if err != nil { t.Fatalf("create %q: %s", fpath, err) } + defer f.Close() // Can't make directory named after file. err = MkdirAll(fpath, 0777) @@ -43,8 +45,8 @@ func TestMkdirAll(t *testing.T) { if !ok { t.Fatalf("MkdirAll %q returned %T, not *PathError", fpath, err) } - if perr.Path != fpath { - t.Fatalf("MkdirAll %q returned wrong error path: %q not %q", fpath, perr.Path, fpath) + if filepath.Clean(perr.Path) != filepath.Clean(fpath) { + t.Fatalf("MkdirAll %q returned wrong error path: %q not %q", fpath, filepath.Clean(perr.Path), filepath.Clean(fpath)) } // Can't make subdirectory of file. @@ -57,8 +59,16 @@ func TestMkdirAll(t *testing.T) { if !ok { t.Fatalf("MkdirAll %q returned %T, not *PathError", ffpath, err) } - if perr.Path != fpath { - t.Fatalf("MkdirAll %q returned wrong error path: %q not %q", ffpath, perr.Path, fpath) + if filepath.Clean(perr.Path) != filepath.Clean(fpath) { + t.Fatalf("MkdirAll %q returned wrong error path: %q not %q", ffpath, filepath.Clean(perr.Path), filepath.Clean(fpath)) + } + + if syscall.OS == "windows" { + path := `_test\_TestMkdirAll_\dir\.\dir2\` + err := MkdirAll(path, 0777) + if err != nil { + t.Fatalf("MkdirAll %q: %s", path, err) + } } } diff --git a/src/pkg/os/path_unix.go b/src/pkg/os/path_unix.go new file mode 100644 index 000000000..0d327cddd --- /dev/null +++ b/src/pkg/os/path_unix.go @@ -0,0 +1,15 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package os + +const ( + PathSeparator = '/' // OS-specific path separator + PathListSeparator = ':' // OS-specific path list separator +) + +// IsPathSeparator returns true if c is a directory separator character. +func IsPathSeparator(c uint8) bool { + return PathSeparator == c +} diff --git a/src/pkg/os/path_windows.go b/src/pkg/os/path_windows.go new file mode 100644 index 000000000..8740a9e61 --- /dev/null +++ b/src/pkg/os/path_windows.go @@ -0,0 +1,16 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package os + +const ( + PathSeparator = '\\' // OS-specific path separator + PathListSeparator = ':' // OS-specific path list separator +) + +// IsPathSeparator returns true if c is a directory separator character. +func IsPathSeparator(c uint8) bool { + // NOTE: Windows accept / as path separator. + return c == '\\' || c == '/' +} diff --git a/src/pkg/os/signal/Makefile b/src/pkg/os/signal/Makefile index 013b91a85..26f58760e 100644 --- a/src/pkg/os/signal/Makefile +++ b/src/pkg/os/signal/Makefile @@ -7,11 +7,5 @@ include ../../../Make.inc TARG=os/signal GOFILES=\ signal.go\ - unix.go\ - -CLEANFILES+=unix.go include ../../../Make.pkg - -unix.go: ../../syscall/zerrors_$(GOOS)_$(GOARCH).go - ./mkunix.sh $< > $@ || rm -f $@ diff --git a/src/pkg/os/signal/signal.go b/src/pkg/os/signal/signal.go index 666c03e73..520f3f8a9 100644 --- a/src/pkg/os/signal/signal.go +++ b/src/pkg/os/signal/signal.go @@ -6,35 +6,20 @@ package signal import ( + "os" "runtime" - "strconv" ) -// A Signal can represent any operating system signal. -type Signal interface { - String() string -} - -type UnixSignal int32 - -func (sig UnixSignal) String() string { - s := runtime.Signame(int32(sig)) - if len(s) > 0 { - return s - } - return "Signal " + strconv.Itoa(int(sig)) -} - // Incoming is the global signal channel. // All signals received by the program will be delivered to this channel. -var Incoming <-chan Signal +var Incoming <-chan os.Signal -func process(ch chan<- 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 <- UnixSignal(sig) + ch <- os.UnixSignal(sig) } } } @@ -42,7 +27,7 @@ func process(ch chan<- Signal) { func init() { runtime.Siginit() - ch := make(chan Signal) // Done here so Incoming can have type <-chan Signal + ch := make(chan os.Signal) // Done here so Incoming can have type <-chan Signal Incoming = ch go process(ch) } diff --git a/src/pkg/os/signal/signal_test.go b/src/pkg/os/signal/signal_test.go index f2679f14d..00eb29578 100644 --- a/src/pkg/os/signal/signal_test.go +++ b/src/pkg/os/signal/signal_test.go @@ -5,6 +5,7 @@ package signal import ( + "os" "syscall" "testing" ) @@ -13,7 +14,7 @@ func TestSignal(t *testing.T) { // Send this process a SIGHUP. syscall.Syscall(syscall.SYS_KILL, uintptr(syscall.Getpid()), syscall.SIGHUP, 0) - if sig := (<-Incoming).(UnixSignal); sig != SIGHUP { - t.Errorf("signal was %v, want %v", sig, SIGHUP) + if sig := (<-Incoming).(os.UnixSignal); sig != os.SIGHUP { + t.Errorf("signal was %v, want %v", sig, os.SIGHUP) } } diff --git a/src/pkg/os/user/user_test.go b/src/pkg/os/user/user_test.go index 2c142bf18..ee917b57a 100644 --- a/src/pkg/os/user/user_test.go +++ b/src/pkg/os/user/user_test.go @@ -42,7 +42,7 @@ func TestLookup(t *testing.T) { } fi, err := os.Stat(u.HomeDir) if err != nil || !fi.IsDirectory() { - t.Errorf("expected a valid HomeDir; stat(%q): err=%v, IsDirectory=%v", err, fi.IsDirectory()) + t.Errorf("expected a valid HomeDir; stat(%q): err=%v, IsDirectory=%v", u.HomeDir, err, fi.IsDirectory()) } if u.Username == "" { t.Fatalf("didn't get a username") @@ -56,6 +56,6 @@ func TestLookup(t *testing.T) { 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) + "Lookup(%q): %#v\n", uid, u, u.Username, un) } } |