blob: 304016b6886813fc72f7c77a6242750893eab0a8 [file] [log] [blame]
Don Newton98fd8812019-09-23 15:15:02 -04001// 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 linux netbsd openbsd solaris
6
7package unix
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}