Skip to content

Commit 28a3732

Browse files
committed
Move readColonFile to separate file
Plan9 operating system stores users and groups information in /adm/users file. This file is similar in strucuture to unix based /etc/passwd and /etc/group. Since readColonFile resides in lookup_unix.go file, extracting it makes it possible to reuse the functionality across all os targets that can can utilize the function.
1 parent d75048f commit 28a3732

File tree

2 files changed

+86
-75
lines changed

2 files changed

+86
-75
lines changed

src/os/user/lookup_unix.go

Lines changed: 0 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99
package user
1010

1111
import (
12-
"bufio"
1312
"bytes"
1413
"errors"
1514
"io"
@@ -27,80 +26,6 @@ func init() {
2726
groupImplemented = false
2827
}
2928

30-
// lineFunc returns a value, an error, or (nil, nil) to skip the row.
31-
type lineFunc func(line []byte) (v interface{}, err error)
32-
33-
// readColonFile parses r as an /etc/group or /etc/passwd style file, running
34-
// fn for each row. readColonFile returns a value, an error, or (nil, nil) if
35-
// the end of the file is reached without a match.
36-
//
37-
// readCols is the minimum number of colon-separated fields that will be passed
38-
// to fn; in a long line additional fields may be silently discarded.
39-
func readColonFile(r io.Reader, fn lineFunc, readCols int) (v interface{}, err error) {
40-
rd := bufio.NewReader(r)
41-
42-
// Read the file line-by-line.
43-
for {
44-
var isPrefix bool
45-
var wholeLine []byte
46-
47-
// Read the next line. We do so in chunks (as much as reader's
48-
// buffer is able to keep), check if we read enough columns
49-
// already on each step and store final result in wholeLine.
50-
for {
51-
var line []byte
52-
line, isPrefix, err = rd.ReadLine()
53-
54-
if err != nil {
55-
// We should return (nil, nil) if EOF is reached
56-
// without a match.
57-
if err == io.EOF {
58-
err = nil
59-
}
60-
return nil, err
61-
}
62-
63-
// Simple common case: line is short enough to fit in a
64-
// single reader's buffer.
65-
if !isPrefix && len(wholeLine) == 0 {
66-
wholeLine = line
67-
break
68-
}
69-
70-
wholeLine = append(wholeLine, line...)
71-
72-
// Check if we read the whole line (or enough columns)
73-
// already.
74-
if !isPrefix || bytes.Count(wholeLine, []byte{':'}) >= readCols {
75-
break
76-
}
77-
}
78-
79-
// There's no spec for /etc/passwd or /etc/group, but we try to follow
80-
// the same rules as the glibc parser, which allows comments and blank
81-
// space at the beginning of a line.
82-
wholeLine = bytes.TrimSpace(wholeLine)
83-
if len(wholeLine) == 0 || wholeLine[0] == '#' {
84-
continue
85-
}
86-
v, err = fn(wholeLine)
87-
if v != nil || err != nil {
88-
return
89-
}
90-
91-
// If necessary, skip the rest of the line
92-
for ; isPrefix; _, isPrefix, err = rd.ReadLine() {
93-
if err != nil {
94-
// We should return (nil, nil) if EOF is reached without a match.
95-
if err == io.EOF {
96-
err = nil
97-
}
98-
return nil, err
99-
}
100-
}
101-
}
102-
}
103-
10429
func matchGroupIndexValue(value string, idx int) lineFunc {
10530
var leadColon string
10631
if idx > 0 {

src/os/user/read_colon_file.go

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
//go:build !windows
2+
// +build !windows
3+
4+
package user
5+
6+
import (
7+
"bufio"
8+
"bytes"
9+
"io"
10+
)
11+
12+
// lineFunc returns a value, an error, or (nil, nil) to skip the row.
13+
type lineFunc func(line []byte) (v interface{}, err error)
14+
15+
// readColonFile parses r as an /etc/group or /etc/passwd style file, running
16+
// fn for each row. readColonFile returns a value, an error, or (nil, nil) if
17+
// the end of the file is reached without a match.
18+
//
19+
// readCols is the minimum number of colon-separated fields that will be passed
20+
// to fn; in a long line additional fields may be silently discarded.
21+
//
22+
// readColonFile can also be used to read /adm/users on plan9.
23+
func readColonFile(r io.Reader, fn lineFunc, readCols int) (v interface{}, err error) {
24+
rd := bufio.NewReader(r)
25+
26+
// Read the file line-by-line.
27+
for {
28+
var isPrefix bool
29+
var wholeLine []byte
30+
31+
// Read the next line. We do so in chunks (as much as reader's
32+
// buffer is able to keep), check if we read enough columns
33+
// already on each step and store final result in wholeLine.
34+
for {
35+
var line []byte
36+
line, isPrefix, err = rd.ReadLine()
37+
38+
if err != nil {
39+
// We should return (nil, nil) if EOF is reached
40+
// without a match.
41+
if err == io.EOF {
42+
err = nil
43+
}
44+
return nil, err
45+
}
46+
47+
// Simple common case: line is short enough to fit in a
48+
// single reader's buffer.
49+
if !isPrefix && len(wholeLine) == 0 {
50+
wholeLine = line
51+
break
52+
}
53+
54+
wholeLine = append(wholeLine, line...)
55+
56+
// Check if we read the whole line (or enough columns)
57+
// already.
58+
if !isPrefix || bytes.Count(wholeLine, []byte{':'}) >= readCols {
59+
break
60+
}
61+
}
62+
63+
// There's no spec for /etc/passwd or /etc/group, but we try to follow
64+
// the same rules as the glibc parser, which allows comments and blank
65+
// space at the beginning of a line.
66+
wholeLine = bytes.TrimSpace(wholeLine)
67+
if len(wholeLine) == 0 || wholeLine[0] == '#' {
68+
continue
69+
}
70+
v, err = fn(wholeLine)
71+
if v != nil || err != nil {
72+
return
73+
}
74+
75+
// If necessary, skip the rest of the line
76+
for ; isPrefix; _, isPrefix, err = rd.ReadLine() {
77+
if err != nil {
78+
// We should return (nil, nil) if EOF is reached without a match.
79+
if err == io.EOF {
80+
err = nil
81+
}
82+
return nil, err
83+
}
84+
}
85+
}
86+
}

0 commit comments

Comments
 (0)