]> Cypherpunks repositories - gostls13.git/commitdiff
First pass at reading directories.
authorRob Pike <r@golang.org>
Sun, 8 Feb 2009 18:18:50 +0000 (10:18 -0800)
committerRob Pike <r@golang.org>
Sun, 8 Feb 2009 18:18:50 +0000 (10:18 -0800)
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

src/lib/os/Makefile
src/lib/os/dir_amd64_darwin.go [new file with mode: 0644]
src/lib/os/dir_amd64_linux.go [new file with mode: 0644]
src/lib/os/os_test.go
src/lib/syscall/file_darwin.go
src/lib/syscall/file_linux.go
src/lib/syscall/types_amd64_darwin.go
src/lib/syscall/types_amd64_linux.go

index c8c8e8839f55851383adea5afd0e6d54304702a2..c284b9cc6c270d726fb49cdc637ed009a8ad1930 100644 (file)
@@ -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 (file)
index 0000000..2671602
--- /dev/null
@@ -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 (file)
index 0000000..65bc796
--- /dev/null
@@ -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;
+}
index beaa227538373533bf625c252261f2944a46f888..2fc4b617cb990cb0520420353d318a04b223e0e1 100644 (file)
@@ -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);
+               }
+       }
+}
index c7087c0360b2984a6444519c25ec76d6c694c960..5d128f743ce4d38ea6a04565a9baf09d2b912b7f 100644 (file)
@@ -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;
+}
index 52c1e90402be42eccad1c6a8cf153386fa71e38e..ceb0a85d7694312618de059c07701941facbe8ef 100644 (file)
@@ -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;
+}
+
index 963759bc67b17851641ac5584e10959f806aecc6..dedf63f363b812b5b20027c55eb3051b64b3e87a 100644 (file)
@@ -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
 
index 2961a338a2188793626505f9b5ef861c6377ab96..a83c8ef835d2f374dccb1c718f94652f78e4cf52 100644 (file)
@@ -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