Source file src/syscall/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 unix || (js && wasm) || wasip1
     6  
     7  package syscall
     8  
     9  import (
    10  	"internal/byteorder"
    11  	"internal/goarch"
    12  	"runtime"
    13  	"unsafe"
    14  )
    15  
    16  // readInt returns the size-bytes unsigned integer in native byte order at offset off.
    17  func readInt(b []byte, off, size uintptr) (u uint64, ok bool) {
    18  	if len(b) < int(off+size) {
    19  		return 0, false
    20  	}
    21  	if goarch.BigEndian {
    22  		return readIntBE(b[off:], size), true
    23  	}
    24  	return readIntLE(b[off:], size), true
    25  }
    26  
    27  func readIntBE(b []byte, size uintptr) uint64 {
    28  	switch size {
    29  	case 1:
    30  		return uint64(b[0])
    31  	case 2:
    32  		return uint64(byteorder.BeUint16(b))
    33  	case 4:
    34  		return uint64(byteorder.BeUint32(b))
    35  	case 8:
    36  		return uint64(byteorder.BeUint64(b))
    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  		return uint64(byteorder.LeUint16(b))
    48  	case 4:
    49  		return uint64(byteorder.LeUint32(b))
    50  	case 8:
    51  		return uint64(byteorder.LeUint64(b))
    52  	default:
    53  		panic("syscall: readInt with unsupported size")
    54  	}
    55  }
    56  
    57  // ParseDirent parses up to max directory entries in buf,
    58  // appending the names to names. It returns the number of
    59  // bytes consumed from buf, the number of entries added
    60  // to names, and the new names slice.
    61  func ParseDirent(buf []byte, max int, names []string) (consumed int, count int, newnames []string) {
    62  	origlen := len(buf)
    63  	count = 0
    64  	for max != 0 && len(buf) > 0 {
    65  		reclen, ok := direntReclen(buf)
    66  		if !ok || reclen > uint64(len(buf)) {
    67  			return origlen, count, names
    68  		}
    69  		rec := buf[:reclen]
    70  		buf = buf[reclen:]
    71  		ino, ok := direntIno(rec)
    72  		if !ok {
    73  			break
    74  		}
    75  		// See src/os/dir_unix.go for the reason why this condition is
    76  		// excluded on wasip1.
    77  		if ino == 0 && runtime.GOOS != "wasip1" { // File absent in directory.
    78  			continue
    79  		}
    80  		const namoff = uint64(unsafe.Offsetof(Dirent{}.Name))
    81  		namlen, ok := direntNamlen(rec)
    82  		if !ok || namoff+namlen > uint64(len(rec)) {
    83  			break
    84  		}
    85  		name := rec[namoff : namoff+namlen]
    86  		for i, c := range name {
    87  			if c == 0 {
    88  				name = name[:i]
    89  				break
    90  			}
    91  		}
    92  		// Check for useless names before allocating a string.
    93  		if string(name) == "." || string(name) == ".." {
    94  			continue
    95  		}
    96  		max--
    97  		count++
    98  		names = append(names, string(name))
    99  	}
   100  	return origlen - len(buf), count, names
   101  }
   102  

View as plain text