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 darwin dragonfly freebsd linux nacl netbsd openbsd solaris 6 7 package os 8 9 import ( 10 "io" 11 "runtime" 12 "syscall" 13 ) 14 15 const ( 16 blockSize = 4096 17 ) 18 19 func (f *File) readdir(n int) (fi []FileInfo, err error) { 20 dirname := f.name 21 if dirname == "" { 22 dirname = "." 23 } 24 names, err := f.Readdirnames(n) 25 fi = make([]FileInfo, 0, len(names)) 26 for _, filename := range names { 27 fip, lerr := lstat(dirname + "/" + filename) 28 if IsNotExist(lerr) { 29 // File disappeared between readdir + stat. 30 // Just treat it as if it didn't exist. 31 continue 32 } 33 if lerr != nil { 34 return fi, lerr 35 } 36 fi = append(fi, fip) 37 } 38 if len(fi) == 0 && err == nil && n > 0 { 39 // Per File.Readdir, the slice must be non-empty or err 40 // must be non-nil if n > 0. 41 err = io.EOF 42 } 43 return fi, err 44 } 45 46 func (f *File) readdirnames(n int) (names []string, err error) { 47 // If this file has no dirinfo, create one. 48 if f.dirinfo == nil { 49 f.dirinfo = new(dirInfo) 50 // The buffer must be at least a block long. 51 f.dirinfo.buf = make([]byte, blockSize) 52 } 53 d := f.dirinfo 54 55 size := n 56 if size <= 0 { 57 size = 100 58 n = -1 59 } 60 61 names = make([]string, 0, size) // Empty with room to grow. 62 for n != 0 { 63 // Refill the buffer if necessary 64 if d.bufp >= d.nbuf { 65 d.bufp = 0 66 var errno error 67 d.nbuf, errno = f.pfd.ReadDirent(d.buf) 68 runtime.KeepAlive(f) 69 if errno != nil { 70 return names, wrapSyscallError("readdirent", errno) 71 } 72 if d.nbuf <= 0 { 73 break // EOF 74 } 75 } 76 77 // Drain the buffer 78 var nb, nc int 79 nb, nc, names = syscall.ParseDirent(d.buf[d.bufp:d.nbuf], n, names) 80 d.bufp += nb 81 n -= nc 82 } 83 if n >= 0 && len(names) == 0 { 84 return names, io.EOF 85 } 86 return names, nil 87 } 88