diff options
author | Ondřej Surý <ondrej@sury.org> | 2011-05-23 09:45:29 +0200 |
---|---|---|
committer | Ondřej Surý <ondrej@sury.org> | 2011-05-23 09:45:29 +0200 |
commit | 63d29fefab5290dc96e0a03ff70603aefa995887 (patch) | |
tree | 95da0105686f9aba568a72e7a8ebd580a4fda20e /src/pkg/os | |
parent | ad811fbb8897a9a3063274e927133915941f1dca (diff) | |
download | golang-63d29fefab5290dc96e0a03ff70603aefa995887.tar.gz |
Imported Upstream version 2011.05.22upstream-weekly/2011.05.22
Diffstat (limited to 'src/pkg/os')
-rw-r--r-- | src/pkg/os/dir_unix.go | 43 | ||||
-rw-r--r-- | src/pkg/os/dir_windows.go | 12 | ||||
-rw-r--r-- | src/pkg/os/env.go | 2 | ||||
-rw-r--r-- | src/pkg/os/env_unix.go | 30 | ||||
-rw-r--r-- | src/pkg/os/file_unix.go | 27 | ||||
-rw-r--r-- | src/pkg/os/file_windows.go | 33 | ||||
-rw-r--r-- | src/pkg/os/os_test.go | 7 | ||||
-rw-r--r-- | src/pkg/os/path.go | 3 | ||||
-rw-r--r-- | src/pkg/os/user/user_test.go | 4 |
9 files changed, 114 insertions, 47 deletions
diff --git a/src/pkg/os/dir_unix.go b/src/pkg/os/dir_unix.go index f5b82230d..9c543838e 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 + d := f.dirinfo + wantAll := n < 0 + + size := n if size < 0 { size = 100 } + 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 !wantAll && 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..a4df9d3ea 100644 --- a/src/pkg/os/dir_windows.go +++ b/src/pkg/os/dir_windows.go @@ -4,14 +4,16 @@ 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) + // If n > 0 and we get an error, we return now. + // If n < 0, we return whatever we got + any error. + if n > 0 && err != nil { + return nil, err } 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_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/file_unix.go b/src/pkg/os/file_unix.go index 2fb28df65..c65c5b3ff 100644 --- a/src/pkg/os/file_unix.go +++ b/src/pkg/os/file_unix.go @@ -70,19 +70,29 @@ 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 +// 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 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, 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 + wantAll := n < 0 + names, namesErr := file.Readdirnames(n) + if namesErr != nil && !wantAll { + return nil, namesErr } fi = make([]FileInfo, len(names)) for i, filename := range names { @@ -93,6 +103,9 @@ func (file *File) Readdir(count int) (fi []FileInfo, err Error) { fi[i] = *fip } } + if !wantAll && namesErr != EOF { + err = namesErr + } return } diff --git a/src/pkg/os/file_windows.go b/src/pkg/os/file_windows.go index 95f60b735..74ff3eb88 100644 --- a/src/pkg/os/file_windows.go +++ b/src/pkg/os/file_windows.go @@ -124,11 +124,20 @@ 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 +// 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 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, 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,13 @@ func (file *File) Readdir(count int) (fi []FileInfo, err Error) { return nil, &PathError{"Readdir", file.name, ENOTDIR} } di := file.dirinfo - size := count + wantAll := n < 0 + size := n if size < 0 { 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 +160,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 +173,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/os_test.go b/src/pkg/os/os_test.go index 65475c118..b06d57b85 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++ diff --git a/src/pkg/os/path.go b/src/pkg/os/path.go index 0eb3ee503..5565aaa29 100644 --- a/src/pkg/os/path.go +++ b/src/pkg/os/path.go @@ -95,6 +95,9 @@ func RemoveAll(path string) Error { err = err1 } } + if err1 == EOF { + break + } // If Readdirnames returned an error, use it. if err == nil { err = err1 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) } } |