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
6// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris
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}
104