// Read a buffer (dir) into the pointer to the DirentBuf, `db` // Returns remaining buffer size and number of entries created // It's a modified version of syscall.ParseDirent in Go's standard library func ParseDir(buf []byte, max int64, db *[]syscall.Dirent) (int, int) { orig := len(buf) i := int64(0) for max != 0 && len(buf) > 0 { dirent := *(*syscall.Dirent)(unsafe.Pointer(&buf[0])) buf = buf[dirent.Reclen:] if dirent.Ino == 0 { continue } b := (*[257]byte)(unsafe.Pointer(&dirent.Name[0])) bn := string(b[0:general.Clen(b[:])]) if bn == "." || bn == ".." { continue } if len(*db) <= int(i) { *db = append(*db, dirent) } else { (*db)[i] = dirent } max-- i++ } return orig - len(buf), int(i) }
// recursively walk through the named directory `dir` until the correct device // is found. // Directories in []searchDevs are automatically skipped func checkDirs(dir string) (string, error) { var ( rs string nameBuf = make([]byte, 256) dirBuf = make([]syscall.Dirent, 256) ) fi, err := os.Open(dir) if err != nil { return "", err } defer fi.Close() err = dirent.ReadDir(int(fi.Fd()), -1, &dirBuf) if err != nil && err != io.EOF { return "", err } for _, v := range dirBuf { // quickly skip most entries if v.Ino != Stat.Ino { continue } _ = copy(nameBuf, general.Int8ToByte(v.Name[:])) name := path.Join(dir, string(nameBuf[:general.Clen(nameBuf)])) // Directories to skip if name == "/dev/stderr" || name == "/dev/stdin" || name == "/dev/stdout" || (len(name) >= 8 && name[0:8] == "/dev/fd/") { continue } // We have to stat the file to determine its Rdev fstat := new(syscall.Stat_t) err = syscall.Stat(name, fstat) if err != nil { continue } // file mode sans permission bits fmode := os.FileMode(fstat.Mode) if fmode.IsDir() { rs, err = checkDirs(name) if err != nil { continue } return rs, nil } if fmode&os.ModeCharDevice == 0 && fstat.Ino == Stat.Ino && fstat.Rdev == Stat.Rdev { return name, nil } } return "", ErrNotFound }
// Return stringified version of a username. // Trims after first null byte func (u *Utmp) ExtractTrimmedName() string { return string(u.User[:general.Clen(u.User[:])]) }