github.com/geraldss/go/src@v0.0.0-20210511222824-ac7d0ebfc235/os/dir_unix.go (about) 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 5 // +build aix dragonfly freebsd js,wasm linux netbsd openbsd solaris 6 7 package os 8 9 import ( 10 "io" 11 "runtime" 12 "syscall" 13 "unsafe" 14 ) 15 16 // Auxiliary information if the File describes a directory 17 type dirInfo struct { 18 buf []byte // buffer for directory I/O 19 nbuf int // length of buf; return value from Getdirentries 20 bufp int // location of next record in buf. 21 } 22 23 const ( 24 // More than 5760 to work around https://golang.org/issue/24015. 25 blockSize = 8192 26 ) 27 28 func (d *dirInfo) close() {} 29 30 func (f *File) readdir(n int, mode readdirMode) (names []string, dirents []DirEntry, infos []FileInfo, err error) { 31 // If this file has no dirinfo, create one. 32 if f.dirinfo == nil { 33 f.dirinfo = new(dirInfo) 34 // The buffer must be at least a block long. 35 f.dirinfo.buf = make([]byte, blockSize) 36 } 37 d := f.dirinfo 38 39 // Change the meaning of n for the implementation below. 40 // 41 // The n above was for the public interface of "if n <= 0, 42 // Readdir returns all the FileInfo from the directory in a 43 // single slice". 44 // 45 // But below, we use only negative to mean looping until the 46 // end and positive to mean bounded, with positive 47 // terminating at 0. 48 if n == 0 { 49 n = -1 50 } 51 52 for n != 0 { 53 // Refill the buffer if necessary 54 if d.bufp >= d.nbuf { 55 d.bufp = 0 56 var errno error 57 d.nbuf, errno = f.pfd.ReadDirent(d.buf) 58 runtime.KeepAlive(f) 59 if errno != nil { 60 return names, dirents, infos, &PathError{Op: "readdirent", Path: f.name, Err: errno} 61 } 62 if d.nbuf <= 0 { 63 break // EOF 64 } 65 } 66 67 // Drain the buffer 68 buf := d.buf[d.bufp:d.nbuf] 69 reclen, ok := direntReclen(buf) 70 if !ok || reclen > uint64(len(buf)) { 71 break 72 } 73 rec := buf[:reclen] 74 d.bufp += int(reclen) 75 ino, ok := direntIno(rec) 76 if !ok { 77 break 78 } 79 if ino == 0 { 80 continue 81 } 82 const namoff = uint64(unsafe.Offsetof(syscall.Dirent{}.Name)) 83 namlen, ok := direntNamlen(rec) 84 if !ok || namoff+namlen > uint64(len(rec)) { 85 break 86 } 87 name := rec[namoff : namoff+namlen] 88 for i, c := range name { 89 if c == 0 { 90 name = name[:i] 91 break 92 } 93 } 94 // Check for useless names before allocating a string. 95 if string(name) == "." || string(name) == ".." { 96 continue 97 } 98 if n > 0 { // see 'n == 0' comment above 99 n-- 100 } 101 if mode == readdirName { 102 names = append(names, string(name)) 103 } else if mode == readdirDirEntry { 104 de, err := newUnixDirent(f.name, string(name), direntType(rec)) 105 if IsNotExist(err) { 106 // File disappeared between readdir and stat. 107 // Treat as if it didn't exist. 108 continue 109 } 110 if err != nil { 111 return nil, dirents, nil, err 112 } 113 dirents = append(dirents, de) 114 } else { 115 info, err := lstat(f.name + "/" + string(name)) 116 if IsNotExist(err) { 117 // File disappeared between readdir + stat. 118 // Treat as if it didn't exist. 119 continue 120 } 121 if err != nil { 122 return nil, nil, infos, err 123 } 124 infos = append(infos, info) 125 } 126 } 127 128 if n > 0 && len(names)+len(dirents)+len(infos) == 0 { 129 return nil, nil, nil, io.EOF 130 } 131 return names, dirents, infos, nil 132 } 133 134 // readInt returns the size-bytes unsigned integer in native byte order at offset off. 135 func readInt(b []byte, off, size uintptr) (u uint64, ok bool) { 136 if len(b) < int(off+size) { 137 return 0, false 138 } 139 if isBigEndian { 140 return readIntBE(b[off:], size), true 141 } 142 return readIntLE(b[off:], size), true 143 } 144 145 func readIntBE(b []byte, size uintptr) uint64 { 146 switch size { 147 case 1: 148 return uint64(b[0]) 149 case 2: 150 _ = b[1] // bounds check hint to compiler; see golang.org/issue/14808 151 return uint64(b[1]) | uint64(b[0])<<8 152 case 4: 153 _ = b[3] // bounds check hint to compiler; see golang.org/issue/14808 154 return uint64(b[3]) | uint64(b[2])<<8 | uint64(b[1])<<16 | uint64(b[0])<<24 155 case 8: 156 _ = b[7] // bounds check hint to compiler; see golang.org/issue/14808 157 return uint64(b[7]) | uint64(b[6])<<8 | uint64(b[5])<<16 | uint64(b[4])<<24 | 158 uint64(b[3])<<32 | uint64(b[2])<<40 | uint64(b[1])<<48 | uint64(b[0])<<56 159 default: 160 panic("syscall: readInt with unsupported size") 161 } 162 } 163 164 func readIntLE(b []byte, size uintptr) uint64 { 165 switch size { 166 case 1: 167 return uint64(b[0]) 168 case 2: 169 _ = b[1] // bounds check hint to compiler; see golang.org/issue/14808 170 return uint64(b[0]) | uint64(b[1])<<8 171 case 4: 172 _ = b[3] // bounds check hint to compiler; see golang.org/issue/14808 173 return uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24 174 case 8: 175 _ = b[7] // bounds check hint to compiler; see golang.org/issue/14808 176 return uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24 | 177 uint64(b[4])<<32 | uint64(b[5])<<40 | uint64(b[6])<<48 | uint64(b[7])<<56 178 default: 179 panic("syscall: readInt with unsupported size") 180 } 181 }