golang.org/x/sys@v0.20.1-0.20240517151509-673e0f94c16d/unix/dirent.go (about) 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 || zos 6 7 package unix 8 9 import "unsafe" 10 11 // readInt returns the size-bytes unsigned integer in native byte order at offset off. 12 func 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 22 func 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 41 func 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. 64 func 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 }