dirent.mx raw

   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  //go:build unix || (js && wasm) || wasip1
   6  
   7  package syscall
   8  
   9  import (
  10  	"internal/byteorder"
  11  	"internal/goarch"
  12  	"runtime"
  13  	"unsafe"
  14  )
  15  
  16  // readInt returns the size-bytes unsigned integer in native byte order at offset off.
  17  func readInt(b []byte, off, size uintptr) (u uint64, ok bool) {
  18  	if len(b) < int(off+size) {
  19  		return 0, false
  20  	}
  21  	if goarch.BigEndian {
  22  		return readIntBE(b[off:], size), true
  23  	}
  24  	return readIntLE(b[off:], size), true
  25  }
  26  
  27  func readIntBE(b []byte, size uintptr) uint64 {
  28  	switch size {
  29  	case 1:
  30  		return uint64(b[0])
  31  	case 2:
  32  		return uint64(byteorder.BEUint16(b))
  33  	case 4:
  34  		return uint64(byteorder.BEUint32(b))
  35  	case 8:
  36  		return uint64(byteorder.BEUint64(b))
  37  	default:
  38  		panic("syscall: readInt with unsupported size")
  39  	}
  40  }
  41  
  42  func readIntLE(b []byte, size uintptr) uint64 {
  43  	switch size {
  44  	case 1:
  45  		return uint64(b[0])
  46  	case 2:
  47  		return uint64(byteorder.LEUint16(b))
  48  	case 4:
  49  		return uint64(byteorder.LEUint32(b))
  50  	case 8:
  51  		return uint64(byteorder.LEUint64(b))
  52  	default:
  53  		panic("syscall: readInt with unsupported size")
  54  	}
  55  }
  56  
  57  // ParseDirent parses up to max directory entries in buf,
  58  // appending the names to names. It returns the number of
  59  // bytes consumed from buf, the number of entries added
  60  // to names, and the new names slice.
  61  func ParseDirent(buf []byte, max int, names []string) (consumed int, count int, newnames []string) {
  62  	origlen := len(buf)
  63  	count = 0
  64  	for max != 0 && len(buf) > 0 {
  65  		reclen, ok := direntReclen(buf)
  66  		if !ok || reclen > uint64(len(buf)) {
  67  			return origlen, count, names
  68  		}
  69  		rec := buf[:reclen]
  70  		buf = buf[reclen:]
  71  		ino, ok := direntIno(rec)
  72  		if !ok {
  73  			break
  74  		}
  75  		// See src/os/dir_unix.go for the reason why this condition is
  76  		// excluded on wasip1.
  77  		if ino == 0 && runtime.GOOS != "wasip1" { // File absent in directory.
  78  			continue
  79  		}
  80  		const namoff = uint64(unsafe.Offsetof(Dirent{}.Name))
  81  		namlen, ok := direntNamlen(rec)
  82  		if !ok || namoff+namlen > uint64(len(rec)) {
  83  			break
  84  		}
  85  		name := rec[namoff : namoff+namlen]
  86  		for i, c := range name {
  87  			if c == 0 {
  88  				name = name[:i]
  89  				break
  90  			}
  91  		}
  92  		// Check for useless names before allocating a string.
  93  		if string(name) == "." || string(name) == ".." {
  94  			continue
  95  		}
  96  		max--
  97  		count++
  98  		names = append(names, string(name))
  99  	}
 100  	return origlen - len(buf), count, names
 101  }
 102