String to byte slice conversion inside loop allocates a new slice each iteration; convert once before the loop
userCommas := []byte("," + u.Username + ",") // ,john,
1// Copyright 2021 The Go Authors. All rights reserved.2// Use of this source code is governed by a BSD-style3// license that can be found in the LICENSE file.45//go:build (((unix && !android) || (js && wasm) || wasip1) && ((!cgo && !darwin) || osusergo)) || aix67package user89import (10 "bufio"11 "bytes"12 "errors"13 "fmt"14 "io"15 "os"16 "strconv"17)1819func listGroupsFromReader(u *User, r io.Reader) ([]string, error) {20 if u.Username == "" {21 return nil, errors.New("user: list groups: empty username")22 }23 primaryGid, err := strconv.Atoi(u.Gid)24 if err != nil {25 return nil, fmt.Errorf("user: list groups for %s: invalid gid %q", u.Username, u.Gid)26 }2728 userCommas := []byte("," + u.Username + ",") // ,john,29 userFirst := userCommas[1:] // john,30 userLast := userCommas[:len(userCommas)-1] // ,john31 userOnly := userCommas[1 : len(userCommas)-1] // john3233 // Add primary Gid first.34 groups := []string{u.Gid}3536 rd := bufio.NewReader(r)37 done := false38 for !done {39 line, err := rd.ReadBytes('\n')40 if err != nil {41 if err == io.EOF {42 done = true43 } else {44 return groups, err45 }46 }4748 // Look for username in the list of users. If user is found,49 // append the GID to the groups slice.5051 // There's no spec for /etc/passwd or /etc/group, but we try to follow52 // the same rules as the glibc parser, which allows comments and blank53 // space at the beginning of a line.54 line = bytes.TrimSpace(line)55 if len(line) == 0 || line[0] == '#' ||56 // If you search for a gid in a row where the group57 // name (the first field) starts with "+" or "-",58 // glibc fails to find the record, and so should we.59 line[0] == '+' || line[0] == '-' {60 continue61 }6263 // Format of /etc/group is64 // groupname:password:GID:user_list65 // for example66 // wheel:x:10:john,paul,jack67 // tcpdump:x:72:68 listIdx := bytes.LastIndexByte(line, ':')69 if listIdx == -1 || listIdx == len(line)-1 {70 // No commas, or empty group list.71 continue72 }73 if bytes.Count(line[:listIdx], colon) != 2 {74 // Incorrect number of colons.75 continue76 }77 list := line[listIdx+1:]78 // Check the list for user without splitting or copying.79 if !(bytes.Equal(list, userOnly) || bytes.HasPrefix(list, userFirst) || bytes.HasSuffix(list, userLast) || bytes.Contains(list, userCommas)) {80 continue81 }8283 // groupname:password:GID84 parts := bytes.Split(line[:listIdx], colon)85 if len(parts) != 3 || len(parts[0]) == 0 {86 continue87 }88 gid := string(parts[2])89 // Make sure it's numeric and not the same as primary GID.90 numGid, err := strconv.Atoi(gid)91 if err != nil || numGid == primaryGid {92 continue93 }9495 groups = append(groups, gid)96 }9798 return groups, nil99}100101func listGroups(u *User) ([]string, error) {102 f, err := os.Open(groupFile)103 if err != nil {104 return nil, err105 }106 defer f.Close()107108 return listGroupsFromReader(u, f)109}
Same data, no extra tab — call code_get_file + code_get_findings over MCP from Claude/Cursor/Copilot.
Generated by searchcode.com · powered by code_get_file + code_get_findings