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.
5 //go:build aix || dragonfly || freebsd || (js && wasm) || wasip1 || linux || netbsd || openbsd || solaris
17 // Auxiliary information if the File describes a directory
19 buf *[]byte // buffer for directory I/O
20 nbuf int // length of buf; return value from Getdirentries
21 bufp int // location of next record in buf.
25 // More than 5760 to work around https://golang.org/issue/24015.
29 var dirBufPool = sync.Pool{
31 // The buffer must be at least a block long.
32 buf := make([]byte, blockSize)
37 func (d *dirInfo) close() {
44 func (f *File) readdir(n int, mode readdirMode) (names []string, dirents []DirEntry, infos []FileInfo, err error) {
45 // If this file has no dirinfo, create one.
47 f.dirinfo = new(dirInfo)
48 f.dirinfo.buf = dirBufPool.Get().(*[]byte)
52 // Change the meaning of n for the implementation below.
54 // The n above was for the public interface of "if n <= 0,
55 // Readdir returns all the FileInfo from the directory in a
58 // But below, we use only negative to mean looping until the
59 // end and positive to mean bounded, with positive
66 // Refill the buffer if necessary
70 d.nbuf, errno = f.pfd.ReadDirent(*d.buf)
73 return names, dirents, infos, &PathError{Op: "readdirent", Path: f.name, Err: errno}
81 buf := (*d.buf)[d.bufp:d.nbuf]
82 reclen, ok := direntReclen(buf)
83 if !ok || reclen > uint64(len(buf)) {
88 ino, ok := direntIno(rec)
92 // When building to wasip1, the host runtime might be running on Windows
93 // or might expose a remote file system which does not have the concept
94 // of inodes. Therefore, we cannot make the assumption that it is safe
95 // to skip entries with zero inodes.
96 if ino == 0 && runtime.GOOS != "wasip1" {
99 const namoff = uint64(unsafe.Offsetof(syscall.Dirent{}.Name))
100 namlen, ok := direntNamlen(rec)
101 if !ok || namoff+namlen > uint64(len(rec)) {
104 name := rec[namoff : namoff+namlen]
105 for i, c := range name {
111 // Check for useless names before allocating a string.
112 if string(name) == "." || string(name) == ".." {
115 if n > 0 { // see 'n == 0' comment above
118 if mode == readdirName {
119 names = append(names, string(name))
120 } else if mode == readdirDirEntry {
121 de, err := newUnixDirent(f.name, string(name), direntType(rec))
123 // File disappeared between readdir and stat.
124 // Treat as if it didn't exist.
128 return nil, dirents, nil, err
130 dirents = append(dirents, de)
132 info, err := lstat(f.name + "/" + string(name))
134 // File disappeared between readdir + stat.
135 // Treat as if it didn't exist.
139 return nil, nil, infos, err
141 infos = append(infos, info)
145 if n > 0 && len(names)+len(dirents)+len(infos) == 0 {
146 return nil, nil, nil, io.EOF
148 return names, dirents, infos, nil
151 // readInt returns the size-bytes unsigned integer in native byte order at offset off.
152 func readInt(b []byte, off, size uintptr) (u uint64, ok bool) {
153 if len(b) < int(off+size) {
157 return readIntBE(b[off:], size), true
159 return readIntLE(b[off:], size), true
162 func readIntBE(b []byte, size uintptr) uint64 {
167 _ = b[1] // bounds check hint to compiler; see golang.org/issue/14808
168 return uint64(b[1]) | uint64(b[0])<<8
170 _ = b[3] // bounds check hint to compiler; see golang.org/issue/14808
171 return uint64(b[3]) | uint64(b[2])<<8 | uint64(b[1])<<16 | uint64(b[0])<<24
173 _ = b[7] // bounds check hint to compiler; see golang.org/issue/14808
174 return uint64(b[7]) | uint64(b[6])<<8 | uint64(b[5])<<16 | uint64(b[4])<<24 |
175 uint64(b[3])<<32 | uint64(b[2])<<40 | uint64(b[1])<<48 | uint64(b[0])<<56
177 panic("syscall: readInt with unsupported size")
181 func readIntLE(b []byte, size uintptr) uint64 {
186 _ = b[1] // bounds check hint to compiler; see golang.org/issue/14808
187 return uint64(b[0]) | uint64(b[1])<<8
189 _ = b[3] // bounds check hint to compiler; see golang.org/issue/14808
190 return uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24
192 _ = b[7] // bounds check hint to compiler; see golang.org/issue/14808
193 return uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24 |
194 uint64(b[4])<<32 | uint64(b[5])<<40 | uint64(b[6])<<48 | uint64(b[7])<<56
196 panic("syscall: readInt with unsupported size")