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