summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRob Pike <r@golang.org>2009-02-08 10:18:50 -0800
committerRob Pike <r@golang.org>2009-02-08 10:18:50 -0800
commit09c50da40220227bd34dcc9cb28100434305174f (patch)
treeb4c649682549e6ef2355f4b82bbb3e326e229925
parent0eb337046a6602996dbc169ff12f4d4fb81fded1 (diff)
downloadgolang-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/Makefile12
-rw-r--r--src/lib/os/dir_amd64_darwin.go58
-rw-r--r--src/lib/os/dir_amd64_linux.go61
-rw-r--r--src/lib/os/os_test.go38
-rw-r--r--src/lib/syscall/file_darwin.go9
-rw-r--r--src/lib/syscall/file_linux.go10
-rw-r--r--src/lib/syscall/types_amd64_darwin.go32
-rw-r--r--src/lib/syscall/types_amd64_linux.go9
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