dirent.go raw

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