Source file src/os/dir_plan9.go

     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  package os
     6  
     7  import (
     8  	"io"
     9  	"io/fs"
    10  	"syscall"
    11  )
    12  
    13  func (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  
    79  type dirEntry struct {
    80  	fs *fileStat
    81  }
    82  
    83  func (de dirEntry) Name() string            { return de.fs.Name() }
    84  func (de dirEntry) IsDir() bool             { return de.fs.IsDir() }
    85  func (de dirEntry) Type() FileMode          { return de.fs.Mode().Type() }
    86  func (de dirEntry) Info() (FileInfo, error) { return de.fs, nil }
    87  
    88  func (de dirEntry) String() string {
    89  	return fs.FormatDirEntry(de)
    90  }
    91  

View as plain text