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 aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris || zos
  6// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris zos
  7
  8package unix
  9
 10import "unsafe"
 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
 61// ParseDirent parses up to max directory entries in buf,
 62// appending the names to names. It returns the number of
 63// bytes consumed from buf, the number of entries added
 64// to names, and the new names slice.
 65func ParseDirent(buf []byte, max int, names []string) (consumed int, count int, newnames []string) {
 66	origlen := len(buf)
 67	count = 0
 68	for max != 0 && len(buf) > 0 {
 69		reclen, ok := direntReclen(buf)
 70		if !ok || reclen > uint64(len(buf)) {
 71			return origlen, count, names
 72		}
 73		rec := buf[:reclen]
 74		buf = buf[reclen:]
 75		ino, ok := direntIno(rec)
 76		if !ok {
 77			break
 78		}
 79		if ino == 0 { // File absent in directory.
 80			continue
 81		}
 82		const namoff = uint64(unsafe.Offsetof(Dirent{}.Name))
 83		namlen, ok := direntNamlen(rec)
 84		if !ok || namoff+namlen > uint64(len(rec)) {
 85			break
 86		}
 87		name := rec[namoff : namoff+namlen]
 88		for i, c := range name {
 89			if c == 0 {
 90				name = name[:i]
 91				break
 92			}
 93		}
 94		// Check for useless names before allocating a string.
 95		if string(name) == "." || string(name) == ".." {
 96			continue
 97		}
 98		max--
 99		count++
100		names = append(names, string(name))
101	}
102	return origlen - len(buf), count, names
103}