diff options
author | Rob Pike <r@golang.org> | 2009-02-08 10:18:50 -0800 |
---|---|---|
committer | Rob Pike <r@golang.org> | 2009-02-08 10:18:50 -0800 |
commit | 09c50da40220227bd34dcc9cb28100434305174f (patch) | |
tree | b4c649682549e6ef2355f4b82bbb3e326e229925 | |
parent | 0eb337046a6602996dbc169ff12f4d4fb81fded1 (diff) | |
download | golang-09c50da40220227bd34dcc9cb28100434305174f.tar.gz |
First pass at reading directories.
Syscall support.
Readdirnames returns array of strings of contents of directory.
R=rsc
DELTA=216 (201 added, 0 deleted, 15 changed)
OCL=24642
CL=24655
-rw-r--r-- | src/lib/os/Makefile | 12 | ||||
-rw-r--r-- | src/lib/os/dir_amd64_darwin.go | 58 | ||||
-rw-r--r-- | src/lib/os/dir_amd64_linux.go | 61 | ||||
-rw-r--r-- | src/lib/os/os_test.go | 38 | ||||
-rw-r--r-- | src/lib/syscall/file_darwin.go | 9 | ||||
-rw-r--r-- | src/lib/syscall/file_linux.go | 10 | ||||
-rw-r--r-- | src/lib/syscall/types_amd64_darwin.go | 32 | ||||
-rw-r--r-- | src/lib/syscall/types_amd64_linux.go | 9 |
8 files changed, 216 insertions, 13 deletions
diff --git a/src/lib/os/Makefile b/src/lib/os/Makefile index c8c8e8839..c284b9cc6 100644 --- a/src/lib/os/Makefile +++ b/src/lib/os/Makefile @@ -4,7 +4,7 @@ # DO NOT EDIT. Automatically generated by gobuild. # gobuild -m os_env.go os_error.go os_file.go os_test.go os_time.go\ -# os_types.go stat_amd64_linux.go >Makefile +# os_types.go stat_amd64_linux.go dir_amd64_linux.go >Makefile O=6 GC=$(O)g CC=$(O)c -w @@ -44,7 +44,10 @@ O2=\ O3=\ os_file.$O\ -os.a: a1 a2 a3 +O4=\ + dir_$(GOARCH)_$(GOOS).$O\ + +os.a: a1 a2 a3 a4 a1: $(O1) $(AR) grc os.a os_error.$O os_types.$O @@ -58,12 +61,17 @@ a3: $(O3) $(AR) grc os.a os_file.$O rm -f $(O3) +a4: $(O4) + $(AR) grc os.a dir_$(GOARCH)_$(GOOS).$O + rm -f $(O4) + newpkg: clean $(AR) grc os.a $(O1): newpkg $(O2): a1 $(O3): a2 +$(O4): a3 nuke: clean rm -f $(GOROOT)/pkg/os.a diff --git a/src/lib/os/dir_amd64_darwin.go b/src/lib/os/dir_amd64_darwin.go new file mode 100644 index 000000000..26716029e --- /dev/null +++ b/src/lib/os/dir_amd64_darwin.go @@ -0,0 +1,58 @@ +// 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. + +package os + +import ( + "syscall"; + "os"; + "unsafe"; +) + +// Negative count means read until EOF. +func Readdirnames(fd *FD, count int) (names []string, err *os.Error) { + // Getdirentries needs the file offset - it's too hard for the kernel to remember + // a number it already has written down. + base, err1 := syscall.Seek(fd.fd, 0, 1); + if err1 != 0 { + return nil, os.ErrnoToError(err1) + } + // The buffer must be at least a block long. + // TODO(r): use fstatfs to find fs block size. + var buf = make([]byte, 8192); + names = make([]string, 0, 100); // TODO: could be smarter about size + for { + if count == 0 { + break + } + ret, err2 := syscall.Getdirentries(fd.fd, &buf[0], len(buf), &base); + if ret < 0 || err2 != 0 { + return names, os.ErrnoToError(err2) + } + if ret == 0 { + break + } + for w, i := uintptr(0),uintptr(0); i < uintptr(ret); i += w { + if count == 0 { + break + } + dir := unsafe.Pointer((uintptr(unsafe.Pointer(&buf[0])) + i)).(*syscall.Dirent); + w = uintptr(dir.Reclen); + if dir.Ino == 0 { + continue + } + count--; + if len(names) == cap(names) { + nnames := make([]string, len(names), 2*len(names)); + for i := 0; i < len(names); i++ { + nnames[i] = names[i] + } + names = nnames; + } + names = names[0:len(names)+1]; + names[len(names)-1] = string(dir.Name[0:dir.Namlen]); + } + } + return names, nil; +} diff --git a/src/lib/os/dir_amd64_linux.go b/src/lib/os/dir_amd64_linux.go new file mode 100644 index 000000000..65bc796bc --- /dev/null +++ b/src/lib/os/dir_amd64_linux.go @@ -0,0 +1,61 @@ +// 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. + +package os + +import ( + "syscall"; + "os"; + "unsafe"; +) + +func clen(n []byte) int { + for i := 0; i < len(n); i++ { + if n[i] == 0 { + return i + } + } + return len(n) +} + +// Negative count means read until EOF. +func Readdirnames(fd *FD, count int) (names []string, err *os.Error) { + // The buffer should be at least a block long. + // TODO(r): use fstatfs to find fs block size. + var buf = make([]syscall.Dirent, 8192/unsafe.Sizeof(*new(syscall.Dirent))); + names = make([]string, 0, 100); // TODO: could be smarter about size + for { + if count == 0 { + break + } + ret, err2 := syscall.Getdents(fd.fd, &buf[0], int64(len(buf) * unsafe.Sizeof(buf[0]))); + if ret < 0 || err2 != 0 { + return names, os.ErrnoToError(err2) + } + if ret == 0 { + break + } + for w, i := uintptr(0),uintptr(0); i < uintptr(ret); i += w { + if count == 0 { + break + } + dir := unsafe.Pointer((uintptr(unsafe.Pointer(&buf[0])) + i)).(*syscall.Dirent); + w = uintptr(dir.Reclen); + if dir.Ino == 0 { + continue + } + count--; + if len(names) == cap(names) { + nnames := make([]string, len(names), 2*len(names)); + for i := 0; i < len(names); i++ { + nnames[i] = names[i] + } + names = nnames; + } + names = names[0:len(names)+1]; + names[len(names)-1] = string(dir.Name[0:clen(dir.Name)]); + } + } + return names, nil; +} diff --git a/src/lib/os/os_test.go b/src/lib/os/os_test.go index beaa22753..2fc4b617c 100644 --- a/src/lib/os/os_test.go +++ b/src/lib/os/os_test.go @@ -77,3 +77,41 @@ func TestLstat(t *testing.T) { t.Error("size should be ", filesize, "; is", dir.Size); } } + +func TestReaddirnames(t *testing.T) { + fd, err := Open(".", O_RDONLY, 0); + defer fd.Close(); + if err != nil { + t.Fatal("open . failed:", err); + } + s, err2 := Readdirnames(fd, -1); + if err2 != nil { + t.Fatal("readdirnames . failed:", err); + } + a := []string{ + "dir_amd64_darwin.go", + "dir_amd64_linux.go", + "os_env.go", + "os_error.go", + "os_file.go", + "os_test.go", + "os_time.go", + "os_types.go", + "stat_amd64_darwin.go", + "stat_amd64_linux.go" + }; + for i, m := range a { + found := false; + for j, n := range s { + if m == n { + if found { + t.Error("present twice:", m); + } + found = true + } + } + if !found { + t.Error("could not find", m); + } + } +} diff --git a/src/lib/syscall/file_darwin.go b/src/lib/syscall/file_darwin.go index c7087c036..5d128f743 100644 --- a/src/lib/syscall/file_darwin.go +++ b/src/lib/syscall/file_darwin.go @@ -40,6 +40,11 @@ func Write(fd int64, buf *byte, nbytes int64) (ret int64, errno int64) { return r1, err; } +func Seek(fd int64, offset int64, whence int64) (ret int64, errno int64) { + r1, r2, err := Syscall(SYS_LSEEK, fd, offset, whence); + return r1, err; +} + func Pipe(fds *[2]int64) (ret int64, errno int64) { r1, r2, err := Syscall(SYS_PIPE, 0, 0, 0); if r1 < 0 { @@ -89,3 +94,7 @@ func Dup2(fd1, fd2 int64) (ret int64, errno int64) { return r1, err; } +func Getdirentries(fd int64, buf *byte, nbytes int64, basep *int64) (ret int64, errno int64) { + r1, r2, err := Syscall6(SYS_GETDIRENTRIES64, fd, int64(uintptr(unsafe.Pointer(buf))), nbytes, int64(uintptr(unsafe.Pointer(basep))), 0, 0); + return r1, err; +} diff --git a/src/lib/syscall/file_linux.go b/src/lib/syscall/file_linux.go index 52c1e9040..ceb0a85d7 100644 --- a/src/lib/syscall/file_linux.go +++ b/src/lib/syscall/file_linux.go @@ -40,6 +40,11 @@ func Write(fd int64, buf *byte, nbytes int64) (ret int64, errno int64) { return r1, err; } +func Seek(fd int64, offset int64, whence int64) (ret int64, errno int64) { + r1, r2, err := Syscall(SYS_LSEEK, fd, offset, whence); + return r1, err; +} + func Pipe(fds *[2]int64) (ret int64, errno int64) { var t [2] int32; r1, r2, err := Syscall(SYS_PIPE, int64(uintptr(unsafe.Pointer(&t[0]))), 0, 0); @@ -90,3 +95,8 @@ func Dup2(fd1, fd2 int64) (ret int64, errno int64) { return r1, err; } +func Getdents(fd int64, buf *Dirent, nbytes int64) (ret int64, errno int64) { + r1, r2, err := Syscall(SYS_GETDENTS64, fd, int64(uintptr(unsafe.Pointer(buf))), nbytes); + return r1, err; +} + diff --git a/src/lib/syscall/types_amd64_darwin.go b/src/lib/syscall/types_amd64_darwin.go index 963759bc6..dedf63f36 100644 --- a/src/lib/syscall/types_amd64_darwin.go +++ b/src/lib/syscall/types_amd64_darwin.go @@ -65,6 +65,8 @@ const ( F_SETFL = 4; FD_CLOEXEC = 1; + + NAME_MAX = 255; ) type Stat_t struct { @@ -76,19 +78,27 @@ type Stat_t struct { Gid uint32; Rdev uint32; Pad1 uint32; - Atime Timespec; - Mtime Timespec; - Ctime Timespec; - Birthtime Timespec; - Size uint64; - Blocks uint64; - Blksize uint32; - Flags uint32; - Gen uint32; - Lspare uint32; - Qspare [2]uint64; + Atime Timespec; + Mtime Timespec; + Ctime Timespec; + Birthtime Timespec; + Size uint64; + Blocks uint64; + Blksize uint32; + Flags uint32; + Gen uint32; + Lspare uint32; + Qspare [2]uint64; } +type Dirent struct { + Ino uint64; + Off uint64; + Reclen uint16; + Namlen uint16; + Type uint8; + Name [NAME_MAX+1]byte; +} // Sockets diff --git a/src/lib/syscall/types_amd64_linux.go b/src/lib/syscall/types_amd64_linux.go index 2961a338a..a83c8ef83 100644 --- a/src/lib/syscall/types_amd64_linux.go +++ b/src/lib/syscall/types_amd64_linux.go @@ -65,6 +65,8 @@ const ( F_SETFL = 4; FD_CLOEXEC = 1; + + NAME_MAX = 255; ) type Stat_t struct { @@ -85,6 +87,13 @@ type Stat_t struct { _unused [3]int64 } +type Dirent struct { + Ino uint64; + Off uint64; + Reclen uint16; + Type uint8; + Name [NAME_MAX+1]byte; +} // Sockets |