dirent_test.go 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150
  1. // Copyright 2019 The Go Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style
  3. // license that can be found in the LICENSE file.
  4. // +build aix darwin dragonfly freebsd linux netbsd openbsd solaris
  5. package unix_test
  6. import (
  7. "bytes"
  8. "fmt"
  9. "io/ioutil"
  10. "os"
  11. "path/filepath"
  12. "runtime"
  13. "sort"
  14. "strconv"
  15. "strings"
  16. "testing"
  17. "unsafe"
  18. "golang.org/x/sys/unix"
  19. )
  20. func TestDirent(t *testing.T) {
  21. const (
  22. direntBufSize = 2048
  23. filenameMinSize = 11
  24. )
  25. d, err := ioutil.TempDir("", "dirent-test")
  26. if err != nil {
  27. t.Fatalf("tempdir: %v", err)
  28. }
  29. defer os.RemoveAll(d)
  30. t.Logf("tmpdir: %s", d)
  31. for i, c := range []byte("0123456789") {
  32. name := string(bytes.Repeat([]byte{c}, filenameMinSize+i))
  33. err = ioutil.WriteFile(filepath.Join(d, name), nil, 0644)
  34. if err != nil {
  35. t.Fatalf("writefile: %v", err)
  36. }
  37. }
  38. buf := bytes.Repeat([]byte("DEADBEAF"), direntBufSize/8)
  39. fd, err := unix.Open(d, unix.O_RDONLY, 0)
  40. if err != nil {
  41. t.Fatalf("Open: %v", err)
  42. }
  43. defer unix.Close(fd)
  44. n, err := unix.ReadDirent(fd, buf)
  45. if err != nil {
  46. t.Fatalf("ReadDirent: %v", err)
  47. }
  48. buf = buf[:n]
  49. names := make([]string, 0, 10)
  50. for len(buf) > 0 {
  51. var bc int
  52. bc, _, names = unix.ParseDirent(buf, -1, names)
  53. if bc == 0 && len(buf) > 0 {
  54. t.Fatal("no progress")
  55. }
  56. buf = buf[bc:]
  57. }
  58. sort.Strings(names)
  59. t.Logf("names: %q", names)
  60. if len(names) != 10 {
  61. t.Errorf("got %d names; expected 10", len(names))
  62. }
  63. for i, name := range names {
  64. ord, err := strconv.Atoi(name[:1])
  65. if err != nil {
  66. t.Fatalf("names[%d] is non-integer %q: %v", i, names[i], err)
  67. }
  68. if expected := string(strings.Repeat(name[:1], filenameMinSize+ord)); name != expected {
  69. t.Errorf("names[%d] is %q (len %d); expected %q (len %d)", i, name, len(name), expected, len(expected))
  70. }
  71. }
  72. }
  73. func TestDirentRepeat(t *testing.T) {
  74. const N = 100
  75. // Note: the size of the buffer is small enough that the loop
  76. // below will need to execute multiple times. See issue #31368.
  77. size := N * unsafe.Offsetof(unix.Dirent{}.Name) / 4
  78. if runtime.GOOS == "freebsd" || runtime.GOOS == "netbsd" {
  79. if size < 1024 {
  80. size = 1024 // DIRBLKSIZ, see issue 31403.
  81. }
  82. if runtime.GOOS == "freebsd" {
  83. t.Skip("need to fix issue 31416 first")
  84. }
  85. }
  86. // Make a directory containing N files
  87. d, err := ioutil.TempDir("", "direntRepeat-test")
  88. if err != nil {
  89. t.Fatalf("tempdir: %v", err)
  90. }
  91. defer os.RemoveAll(d)
  92. var files []string
  93. for i := 0; i < N; i++ {
  94. files = append(files, fmt.Sprintf("file%d", i))
  95. }
  96. for _, file := range files {
  97. err = ioutil.WriteFile(filepath.Join(d, file), []byte("contents"), 0644)
  98. if err != nil {
  99. t.Fatalf("writefile: %v", err)
  100. }
  101. }
  102. // Read the directory entries using ReadDirent.
  103. fd, err := unix.Open(d, unix.O_RDONLY, 0)
  104. if err != nil {
  105. t.Fatalf("Open: %v", err)
  106. }
  107. defer unix.Close(fd)
  108. var files2 []string
  109. for {
  110. buf := make([]byte, size)
  111. n, err := unix.ReadDirent(fd, buf)
  112. if err != nil {
  113. t.Fatalf("ReadDirent: %v", err)
  114. }
  115. if n == 0 {
  116. break
  117. }
  118. buf = buf[:n]
  119. for len(buf) > 0 {
  120. var consumed int
  121. consumed, _, files2 = unix.ParseDirent(buf, -1, files2)
  122. if consumed == 0 && len(buf) > 0 {
  123. t.Fatal("no progress")
  124. }
  125. buf = buf[consumed:]
  126. }
  127. }
  128. // Check results
  129. sort.Strings(files)
  130. sort.Strings(files2)
  131. if strings.Join(files, "|") != strings.Join(files2, "|") {
  132. t.Errorf("bad file list: want\n%q\ngot\n%q", files, files2)
  133. }
  134. }