readdir.mx raw

   1  // Copyright 2020 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 fs
   6  
   7  import (
   8  	"errors"
   9  	"internal/bytealg"
  10  	"slices"
  11  )
  12  
  13  // ReadDirFS is the interface implemented by a file system
  14  // that provides an optimized implementation of [ReadDir].
  15  type ReadDirFS interface {
  16  	FS
  17  
  18  	// ReadDir reads the named directory
  19  	// and returns a list of directory entries sorted by filename.
  20  	ReadDir(name string) ([]DirEntry, error)
  21  }
  22  
  23  // ReadDir reads the named directory
  24  // and returns a list of directory entries sorted by filename.
  25  //
  26  // If fs implements [ReadDirFS], ReadDir calls fs.ReadDir.
  27  // Otherwise ReadDir calls fs.Open and uses ReadDir and Close
  28  // on the returned file.
  29  func ReadDir(fsys FS, name []byte) ([]DirEntry, error) {
  30  	if fsys, ok := fsys.(ReadDirFS); ok {
  31  		return fsys.ReadDir(name)
  32  	}
  33  
  34  	file, err := fsys.Open(name)
  35  	if err != nil {
  36  		return nil, err
  37  	}
  38  	defer file.Close()
  39  
  40  	dir, ok := file.(ReadDirFile)
  41  	if !ok {
  42  		return nil, &PathError{Op: "readdir", Path: name, Err: errors.New("not implemented")}
  43  	}
  44  
  45  	list, err := dir.ReadDir(-1)
  46  	slices.SortFunc(list, func(a, b DirEntry) int {
  47  		return bytealg.CompareString(a.Name(), b.Name())
  48  	})
  49  	return list, err
  50  }
  51  
  52  // dirInfo is a DirEntry based on a FileInfo.
  53  type dirInfo struct {
  54  	fileInfo FileInfo
  55  }
  56  
  57  func (di dirInfo) IsDir() bool {
  58  	return di.fileInfo.IsDir()
  59  }
  60  
  61  func (di dirInfo) Type() FileMode {
  62  	return di.fileInfo.Mode().Type()
  63  }
  64  
  65  func (di dirInfo) Info() (FileInfo, error) {
  66  	return di.fileInfo, nil
  67  }
  68  
  69  func (di dirInfo) Name() []byte {
  70  	return di.fileInfo.Name()
  71  }
  72  
  73  func (di dirInfo) String() string {
  74  	return FormatDirEntry(di)
  75  }
  76  
  77  // FileInfoToDirEntry returns a [DirEntry] that returns information from info.
  78  // If info is nil, FileInfoToDirEntry returns nil.
  79  func FileInfoToDirEntry(info FileInfo) DirEntry {
  80  	if info == nil {
  81  		return nil
  82  	}
  83  	return dirInfo{fileInfo: info}
  84  }
  85