dirent.go

  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
  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}