dirent.go

  1//go:build aix || dragonfly || freebsd || (js && wasm) || linux || netbsd || openbsd || solaris
  2
  3package dirent
  4
  5import (
  6	"os"
  7	"runtime"
  8	"syscall"
  9	"unsafe"
 10)
 11
 12// readInt returns the size-bytes unsigned integer in native byte order at offset off.
 13func readInt(b []byte, off, size uintptr) (u uint64, ok bool) {
 14	if len(b) < int(off+size) {
 15		return 0, false
 16	}
 17	if isBigEndian {
 18		return readIntBE(b[off:], size), true
 19	}
 20	return readIntLE(b[off:], size), true
 21}
 22
 23func readIntBE(b []byte, size uintptr) uint64 {
 24	switch size {
 25	case 1:
 26		return uint64(b[0])
 27	case 2:
 28		_ = b[1] // bounds check hint to compiler; see golang.org/issue/14808
 29		return uint64(b[1]) | uint64(b[0])<<8
 30	case 4:
 31		_ = b[3] // bounds check hint to compiler; see golang.org/issue/14808
 32		return uint64(b[3]) | uint64(b[2])<<8 | uint64(b[1])<<16 | uint64(b[0])<<24
 33	case 8:
 34		_ = b[7] // bounds check hint to compiler; see golang.org/issue/14808
 35		return uint64(b[7]) | uint64(b[6])<<8 | uint64(b[5])<<16 | uint64(b[4])<<24 |
 36			uint64(b[3])<<32 | uint64(b[2])<<40 | uint64(b[1])<<48 | uint64(b[0])<<56
 37	default:
 38		panic("syscall: readInt with unsupported size")
 39	}
 40}
 41
 42func readIntLE(b []byte, size uintptr) uint64 {
 43	switch size {
 44	case 1:
 45		return uint64(b[0])
 46	case 2:
 47		_ = b[1] // bounds check hint to compiler; see golang.org/issue/14808
 48		return uint64(b[0]) | uint64(b[1])<<8
 49	case 4:
 50		_ = b[3] // bounds check hint to compiler; see golang.org/issue/14808
 51		return uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24
 52	case 8:
 53		_ = b[7] // bounds check hint to compiler; see golang.org/issue/14808
 54		return uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24 |
 55			uint64(b[4])<<32 | uint64(b[5])<<40 | uint64(b[6])<<48 | uint64(b[7])<<56
 56	default:
 57		panic("syscall: readInt with unsupported size")
 58	}
 59}
 60
 61const InvalidMode = os.FileMode(1<<32 - 1)
 62
 63func Parse(buf []byte) (consumed int, name string, typ os.FileMode) {
 64
 65	reclen, ok := direntReclen(buf)
 66	if !ok || reclen > uint64(len(buf)) {
 67		// WARN: this is a hard error because we consumed 0 bytes
 68		// and not stopping here could lead to an infinite loop.
 69		return 0, "", InvalidMode
 70	}
 71	consumed = int(reclen)
 72	rec := buf[:reclen]
 73
 74	ino, ok := direntIno(rec)
 75	if !ok {
 76		return consumed, "", InvalidMode
 77	}
 78	// When building to wasip1, the host runtime might be running on Windows
 79	// or might expose a remote file system which does not have the concept
 80	// of inodes. Therefore, we cannot make the assumption that it is safe
 81	// to skip entries with zero inodes.
 82	if ino == 0 && runtime.GOOS != "wasip1" {
 83		return consumed, "", InvalidMode
 84	}
 85
 86	typ = direntType(buf)
 87
 88	const namoff = uint64(unsafe.Offsetof(syscall.Dirent{}.Name))
 89	namlen, ok := direntNamlen(rec)
 90	if !ok || namoff+namlen > uint64(len(rec)) {
 91		return consumed, "", InvalidMode
 92	}
 93	namebuf := rec[namoff : namoff+namlen]
 94	for i, c := range namebuf {
 95		if c == 0 {
 96			namebuf = namebuf[:i]
 97			break
 98		}
 99	}
100	// Check for useless names before allocating a string.
101	if string(namebuf) == "." {
102		name = "."
103	} else if string(namebuf) == ".." {
104		name = ".."
105	} else {
106		name = string(namebuf)
107	}
108	return consumed, name, typ
109}