aboutsummaryrefslogtreecommitdiffstats
path: root/vendor/golang.org/x/sys/unix/dirent.go
blob: bd475812b7af696cc6a6b050e77f913e4fd7b6b3 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
// 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.

// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris

package unix

import "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 isBigEndian {
        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
        }
        if ino == 0 { // 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
}