lookupGroupId: add implementation for go1.6

Signed-off-by: Vincent Batts <vbatts@hashbangbash.com>
This commit is contained in:
Vincent Batts 2017-06-15 12:07:52 -05:00
parent 68651d77d6
commit bbedbb3eaa
4 changed files with 113 additions and 2 deletions

View File

@ -35,7 +35,7 @@ var (
}
stat := info.Sys().(*syscall.Stat_t)
g, err := user.LookupGroupId(fmt.Sprintf("%d", stat.Gid))
g, err := lookupGroupID(fmt.Sprintf("%d", stat.Gid))
if err != nil {
return emptyKV, err
}

View File

@ -40,7 +40,7 @@ var (
}
stat := info.Sys().(*syscall.Stat_t)
g, err := user.LookupGroupId(fmt.Sprintf("%d", stat.Gid))
g, err := lookupGroupID(fmt.Sprintf("%d", stat.Gid))
if err != nil {
return emptyKV, err
}

9
lookup_new.go Normal file
View File

@ -0,0 +1,9 @@
// +build go1.7
package mtree
import (
"os/user"
)
var lookupGroupID = user.LookupGroupId

102
lookup_old.go Normal file
View File

@ -0,0 +1,102 @@
// +build !go1.7
package mtree
import (
"bufio"
"bytes"
"io"
"os"
"strconv"
"strings"
)
const groupFile = "/etc/group"
var colon = []byte{':'}
// Group represents a grouping of users.
//
// On POSIX systems Gid contains a decimal number representing the group ID.
type Group struct {
Gid string // group ID
Name string // group name
}
func lookupGroupID(id string) (*Group, error) {
f, err := os.Open(groupFile)
if err != nil {
return nil, err
}
defer f.Close()
return findGroupID(id, f)
}
func findGroupID(id string, r io.Reader) (*Group, error) {
if v, err := readColonFile(r, matchGroupIndexValue(id, 2)); err != nil {
return nil, err
} else if v != nil {
return v.(*Group), nil
}
return nil, UnknownGroupIDError(id)
}
// lineFunc returns a value, an error, or (nil, nil) to skip the row.
type lineFunc func(line []byte) (v interface{}, err error)
// readColonFile parses r as an /etc/group or /etc/passwd style file, running
// fn for each row. readColonFile returns a value, an error, or (nil, nil) if
// the end of the file is reached without a match.
func readColonFile(r io.Reader, fn lineFunc) (v interface{}, err error) {
bs := bufio.NewScanner(r)
for bs.Scan() {
line := bs.Bytes()
// There's no spec for /etc/passwd or /etc/group, but we try to follow
// the same rules as the glibc parser, which allows comments and blank
// space at the beginning of a line.
line = bytes.TrimSpace(line)
if len(line) == 0 || line[0] == '#' {
continue
}
v, err = fn(line)
if v != nil || err != nil {
return
}
}
return nil, bs.Err()
}
func matchGroupIndexValue(value string, idx int) lineFunc {
var leadColon string
if idx > 0 {
leadColon = ":"
}
substr := []byte(leadColon + value + ":")
return func(line []byte) (v interface{}, err error) {
if !bytes.Contains(line, substr) || bytes.Count(line, colon) < 3 {
return
}
// wheel:*:0:root
parts := strings.SplitN(string(line), ":", 4)
if len(parts) < 4 || parts[0] == "" || parts[idx] != value ||
// If the file contains +foo and you search for "foo", glibc
// returns an "invalid argument" error. Similarly, if you search
// for a gid for a row where the group name starts with "+" or "-",
// glibc fails to find the record.
parts[0][0] == '+' || parts[0][0] == '-' {
return
}
if _, err := strconv.Atoi(parts[2]); err != nil {
return nil, nil
}
return &Group{Name: parts[0], Gid: parts[2]}, nil
}
}
// UnknownGroupIDError is returned by LookupGroupId when
// a group cannot be found.
type UnknownGroupIDError string
func (e UnknownGroupIDError) Error() string {
return "group: unknown groupid " + string(e)
}