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 5package os 6 7import ( 8 "io" 9 "io/fs" 10 "syscall" 11) 12 13func (file *File) readdir(n int, mode readdirMode) (names []string, dirents []DirEntry, infos []FileInfo, err error) { 14 // If this file has no dirinfo, create one. 15 d := file.dirinfo.Load() 16 if d == nil { 17 d = new(dirInfo) 18 file.dirinfo.Store(d) 19 } 20 d.mu.Lock() 21 defer d.mu.Unlock() 22 23 size := n 24 if size <= 0 { 25 size = 100 26 n = -1 27 } 28 for n != 0 { 29 // Refill the buffer if necessary. 30 if d.bufp >= d.nbuf { 31 nb, err := file.Read(d.buf[:]) 32 33 // Update the buffer state before checking for errors. 34 d.bufp, d.nbuf = 0, nb 35 36 if err != nil { 37 if err == io.EOF { 38 break 39 } 40 return names, dirents, infos, &PathError{Op: "readdir", Path: file.name, Err: err} 41 } 42 if nb < syscall.STATFIXLEN { 43 return names, dirents, infos, &PathError{Op: "readdir", Path: file.name, Err: syscall.ErrShortStat} 44 } 45 } 46 47 // Get a record from the buffer. 48 b := d.buf[d.bufp:] 49 m := int(uint16(b[0])|uint16(b[1])<<8) + 2 50 if m < syscall.STATFIXLEN { 51 return names, dirents, infos, &PathError{Op: "readdir", Path: file.name, Err: syscall.ErrShortStat} 52 } 53 54 dir, err := syscall.UnmarshalDir(b[:m]) 55 if err != nil { 56 return names, dirents, infos, &PathError{Op: "readdir", Path: file.name, Err: err} 57 } 58 59 if mode == readdirName { 60 names = append(names, dir.Name) 61 } else { 62 f := fileInfoFromStat(dir) 63 if mode == readdirDirEntry { 64 dirents = append(dirents, dirEntry{f}) 65 } else { 66 infos = append(infos, f) 67 } 68 } 69 d.bufp += m 70 n-- 71 } 72 73 if n > 0 && len(names)+len(dirents)+len(infos) == 0 { 74 return nil, nil, nil, io.EOF 75 } 76 return names, dirents, infos, nil 77} 78 79type dirEntry struct { 80 fs *fileStat 81} 82 83func (de dirEntry) Name() string { return de.fs.Name() } 84func (de dirEntry) IsDir() bool { return de.fs.IsDir() } 85func (de dirEntry) Type() FileMode { return de.fs.Mode().Type() } 86func (de dirEntry) Info() (FileInfo, error) { return de.fs, nil } 87 88func (de dirEntry) String() string { 89 return fs.FormatDirEntry(de) 90} 91