| // Copyright 2009 The Go Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style |
| // license that can be found in the LICENSE file. |
| |
| //go:build unix || (js && wasm) || wasip1 |
| |
| package syscall |
| |
| import ( |
| "internal/goarch" |
| "runtime" |
| "unsafe" |
| ) |
| |
| // readInt returns the size-bytes unsigned integer in native byte order at offset off. |
| func readInt(b []byte, off, size uintptr) (u uint64, ok bool) { |
| if len(b) < int(off+size) { |
| return 0, false |
| } |
| if goarch.BigEndian { |
| return readIntBE(b[off:], size), true |
| } |
| return readIntLE(b[off:], size), true |
| } |
| |
| func readIntBE(b []byte, size uintptr) uint64 { |
| switch size { |
| case 1: |
| return uint64(b[0]) |
| case 2: |
| _ = b[1] // bounds check hint to compiler; see golang.org/issue/14808 |
| return uint64(b[1]) | uint64(b[0])<<8 |
| case 4: |
| _ = b[3] // bounds check hint to compiler; see golang.org/issue/14808 |
| return uint64(b[3]) | uint64(b[2])<<8 | uint64(b[1])<<16 | uint64(b[0])<<24 |
| case 8: |
| _ = b[7] // bounds check hint to compiler; see golang.org/issue/14808 |
| return uint64(b[7]) | uint64(b[6])<<8 | uint64(b[5])<<16 | uint64(b[4])<<24 | |
| uint64(b[3])<<32 | uint64(b[2])<<40 | uint64(b[1])<<48 | uint64(b[0])<<56 |
| default: |
| panic("syscall: readInt with unsupported size") |
| } |
| } |
| |
| func readIntLE(b []byte, size uintptr) uint64 { |
| switch size { |
| case 1: |
| return uint64(b[0]) |
| case 2: |
| _ = b[1] // bounds check hint to compiler; see golang.org/issue/14808 |
| return uint64(b[0]) | uint64(b[1])<<8 |
| case 4: |
| _ = b[3] // bounds check hint to compiler; see golang.org/issue/14808 |
| return uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24 |
| case 8: |
| _ = b[7] // bounds check hint to compiler; see golang.org/issue/14808 |
| return uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24 | |
| uint64(b[4])<<32 | uint64(b[5])<<40 | uint64(b[6])<<48 | uint64(b[7])<<56 |
| default: |
| panic("syscall: readInt with unsupported size") |
| } |
| } |
| |
| // ParseDirent parses up to max directory entries in buf, |
| // appending the names to names. It returns the number of |
| // bytes consumed from buf, the number of entries added |
| // to names, and the new names slice. |
| func ParseDirent(buf []byte, max int, names []string) (consumed int, count int, newnames []string) { |
| origlen := len(buf) |
| count = 0 |
| for max != 0 && len(buf) > 0 { |
| reclen, ok := direntReclen(buf) |
| if !ok || reclen > uint64(len(buf)) { |
| return origlen, count, names |
| } |
| rec := buf[:reclen] |
| buf = buf[reclen:] |
| ino, ok := direntIno(rec) |
| if !ok { |
| break |
| } |
| // See src/os/dir_unix.go for the reason why this condition is |
| // excluded on wasip1. |
| if ino == 0 && runtime.GOOS != "wasip1" { // File absent in directory. |
| continue |
| } |
| const namoff = uint64(unsafe.Offsetof(Dirent{}.Name)) |
| namlen, ok := direntNamlen(rec) |
| if !ok || namoff+namlen > uint64(len(rec)) { |
| break |
| } |
| name := rec[namoff : namoff+namlen] |
| for i, c := range name { |
| if c == 0 { |
| name = name[:i] |
| break |
| } |
| } |
| // Check for useless names before allocating a string. |
| if string(name) == "." || string(name) == ".." { |
| continue |
| } |
| max-- |
| count++ |
| names = append(names, string(name)) |
| } |
| return origlen - len(buf), count, names |
| } |