dir_gccgo.go 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  1. // Copyright 2009 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. package os
  5. import (
  6. "internal/poll"
  7. "io"
  8. "syscall"
  9. "unsafe"
  10. )
  11. // FIXME: pathconf returns long, not int.
  12. //extern pathconf
  13. func libc_pathconf(*byte, int32) int
  14. func direntType(*syscall.Dirent) byte
  15. func clen(n []byte) int {
  16. for i := 0; i < len(n); i++ {
  17. if n[i] == 0 {
  18. return i
  19. }
  20. }
  21. return len(n)
  22. }
  23. func (f *File) readdir(n int, mode readdirMode) (names []string, dirents []DirEntry, infos []FileInfo, err error) {
  24. // If this file has no dirinfo, create one.
  25. if f.dirinfo == nil {
  26. fd, call, err := poll.DupCloseOnExec(int(f.pfd.Sysfd))
  27. if err != nil {
  28. return nil, nil, nil, NewSyscallError(call, err)
  29. }
  30. syscall.Entersyscall()
  31. r := libc_fdopendir(int32(fd))
  32. errno := syscall.GetErrno()
  33. syscall.Exitsyscall()
  34. if r == nil {
  35. return nil, nil, nil, &PathError{"fdopendir", f.name, errno}
  36. }
  37. f.dirinfo = &dirInfo{r}
  38. }
  39. dir := f.dirinfo.dir
  40. // Change the meaning of n for the implementation below.
  41. //
  42. // The n above was for the public interface of "if n <= 0,
  43. // Readdir returns all the FileInfo from the directory in a
  44. // single slice".
  45. //
  46. // But below, we use only negative to mean looping until the
  47. // end and positive to mean bounded, with positive
  48. // terminating at 0.
  49. if n == 0 {
  50. n = -1
  51. }
  52. for n != 0 {
  53. syscall.Entersyscall()
  54. syscall.SetErrno(0)
  55. dirent := libc_readdir(dir)
  56. errno := syscall.GetErrno()
  57. syscall.Exitsyscall()
  58. if dirent == nil {
  59. if errno != 0 {
  60. return names, dirents, infos, &PathError{Op: "readdir", Path: f.name, Err: errno}
  61. }
  62. break // EOF
  63. }
  64. // In some cases the actual name can be longer than
  65. // the Name field.
  66. name := (*[1 << 16]byte)(unsafe.Pointer(&dirent.Name[0]))[:]
  67. for i, c := range name {
  68. if c == 0 {
  69. name = name[:i]
  70. break
  71. }
  72. }
  73. // Check for useless names before allocating a string.
  74. if (len(name) == 1 && name[0] == '.') || (len(name) == 2 && name[0] == '.' && name[1] == '.') {
  75. continue
  76. }
  77. if n > 0 { // see 'n == 0' comment above
  78. n--
  79. }
  80. if mode == readdirName {
  81. names = append(names, string(name))
  82. } else if mode == readdirDirEntry {
  83. var typ FileMode
  84. switch direntType(dirent) {
  85. case 'B':
  86. typ = ModeDevice
  87. case 'C':
  88. typ = ModeDevice | ModeCharDevice
  89. case 'D':
  90. typ = ModeDir
  91. case 'F':
  92. typ = ModeNamedPipe
  93. case 'L':
  94. typ = ModeSymlink
  95. case 'R':
  96. typ = 0
  97. case 'S':
  98. typ = ModeSocket
  99. case 'U':
  100. typ = ^FileMode(0)
  101. }
  102. de, err := newUnixDirent(f.name, string(name), typ)
  103. if IsNotExist(err) {
  104. // File disappeared between readdir and stat.
  105. // Treat as if it didn't exist.
  106. continue
  107. }
  108. if err != nil {
  109. return nil, dirents, nil, err
  110. }
  111. dirents = append(dirents, de)
  112. } else {
  113. info, err := lstat(f.name + "/" + string(name))
  114. if IsNotExist(err) {
  115. // File disappeared between readdir + stat.
  116. // Treat as if it didn't exist.
  117. continue
  118. }
  119. if err != nil {
  120. return nil, nil, infos, err
  121. }
  122. infos = append(infos, info)
  123. }
  124. }
  125. if n > 0 && len(names)+len(dirents)+len(infos) == 0 {
  126. return nil, nil, nil, io.EOF
  127. }
  128. return names, dirents, infos, nil
  129. }