Home | History | Annotate | Download | only in syscall
      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 // +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris
      6 
      7 package syscall
      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