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
7package syscall
8
9import (
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.
17func 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
27func 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
42func 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.
61func 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