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