github.com/Andyfoo/golang/x/sys@v0.0.0-20190901054642-57c1bf301704/unix/dirent.go (about)

     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 aix darwin dragonfly freebsd linux netbsd openbsd solaris
     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  }