Files
sys/unix/dirent_test.go
dustin-ward 95e765b1cc x/sys/unix: make ReadDirent available on zOS
Currently ReadDirent is not available on zOS. This implementation modifies the current darwin implementation to work on zOS.

Also make tests available on zOS.

Fixes golang/go#54528
Fixes golang/go#54587

Change-Id: I62a09d0068ec8c5fdc849a411ce43bdf14ca3926
Reviewed-on: https://go-review.googlesource.com/c/sys/+/424778
Reviewed-by: Ian Lance Taylor <iant@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
Reviewed-by: Joedian Reid <joedian@golang.org>
Reviewed-by: Bill O'Farrell <billotosyr@gmail.com>
Run-TryBot: Ian Lance Taylor <iant@google.com>
Auto-Submit: Ian Lance Taylor <iant@google.com>
2022-10-13 17:17:32 +00:00

152 lines
3.5 KiB
Go

// Copyright 2019 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.
//go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris || zos
// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris zos
package unix_test
import (
"bytes"
"fmt"
"io/ioutil"
"os"
"path/filepath"
"runtime"
"sort"
"strconv"
"strings"
"testing"
"unsafe"
"golang.org/x/sys/unix"
)
func TestDirent(t *testing.T) {
const (
direntBufSize = 2048
filenameMinSize = 11
)
d, err := ioutil.TempDir("", "dirent-test")
if err != nil {
t.Fatalf("tempdir: %v", err)
}
defer os.RemoveAll(d)
t.Logf("tmpdir: %s", d)
for i, c := range []byte("0123456789") {
name := string(bytes.Repeat([]byte{c}, filenameMinSize+i))
err = ioutil.WriteFile(filepath.Join(d, name), nil, 0644)
if err != nil {
t.Fatalf("writefile: %v", err)
}
}
buf := bytes.Repeat([]byte("DEADBEAF"), direntBufSize/8)
fd, err := unix.Open(d, unix.O_RDONLY, 0)
if err != nil {
t.Fatalf("Open: %v", err)
}
defer unix.Close(fd)
n, err := unix.ReadDirent(fd, buf)
if err != nil {
t.Fatalf("ReadDirent: %v", err)
}
buf = buf[:n]
names := make([]string, 0, 10)
for len(buf) > 0 {
var bc int
bc, _, names = unix.ParseDirent(buf, -1, names)
if bc == 0 && len(buf) > 0 {
t.Fatal("no progress")
}
buf = buf[bc:]
}
sort.Strings(names)
t.Logf("names: %q", names)
if len(names) != 10 {
t.Errorf("got %d names; expected 10", len(names))
}
for i, name := range names {
ord, err := strconv.Atoi(name[:1])
if err != nil {
t.Fatalf("names[%d] is non-integer %q: %v", i, names[i], err)
}
if expected := string(strings.Repeat(name[:1], filenameMinSize+ord)); name != expected {
t.Errorf("names[%d] is %q (len %d); expected %q (len %d)", i, name, len(name), expected, len(expected))
}
}
}
func TestDirentRepeat(t *testing.T) {
const N = 100
// Note: the size of the buffer is small enough that the loop
// below will need to execute multiple times. See issue #31368.
size := N * unsafe.Offsetof(unix.Dirent{}.Name) / 4
if runtime.GOOS == "freebsd" || runtime.GOOS == "netbsd" {
if size < 1024 {
size = 1024 // DIRBLKSIZ, see issue 31403.
}
if runtime.GOOS == "freebsd" {
t.Skip("need to fix issue 31416 first")
}
}
// Make a directory containing N files
d, err := ioutil.TempDir("", "direntRepeat-test")
if err != nil {
t.Fatalf("tempdir: %v", err)
}
defer os.RemoveAll(d)
var files []string
for i := 0; i < N; i++ {
files = append(files, fmt.Sprintf("file%d", i))
}
for _, file := range files {
err = ioutil.WriteFile(filepath.Join(d, file), []byte("contents"), 0644)
if err != nil {
t.Fatalf("writefile: %v", err)
}
}
// Read the directory entries using ReadDirent.
fd, err := unix.Open(d, unix.O_RDONLY, 0)
if err != nil {
t.Fatalf("Open: %v", err)
}
defer unix.Close(fd)
var files2 []string
for {
buf := make([]byte, size)
n, err := unix.ReadDirent(fd, buf)
if err != nil {
t.Fatalf("ReadDirent: %v", err)
}
if n == 0 {
break
}
buf = buf[:n]
for len(buf) > 0 {
var consumed int
consumed, _, files2 = unix.ParseDirent(buf, -1, files2)
if consumed == 0 && len(buf) > 0 {
t.Fatal("no progress")
}
buf = buf[consumed:]
}
}
// Check results
sort.Strings(files)
sort.Strings(files2)
if strings.Join(files, "|") != strings.Join(files2, "|") {
t.Errorf("bad file list: want\n%q\ngot\n%q", files, files2)
}
}