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