Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code | Sign in
(1198)

Delta Between Two Patch Sets: src/pkg/os/user/lookup_unix.go

Issue 4589049: code review 4589049: os/user: group lookup functions
Left Patch Set: diff -r 164ef168486b https://go.googlecode.com/hg/ Created 12 years, 9 months ago
Right Patch Set: diff -r 17e26defe7bc https://go.googlecode.com/hg/ Created 12 years, 9 months ago
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments. Please Sign in to add in-line comments.
Jump to:
Left: Side by side diff | Download
Right: Side by side diff | Download
LEFTRIGHT
1 // Copyright 2011 The Go Authors. All rights reserved. 1 // Copyright 2011 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style 2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file. 3 // license that can be found in the LICENSE file.
4 4
5 package user 5 package user
6 6
7 import ( 7 import (
8 "fmt" 8 "fmt"
9 "os" 9 "os"
10 "runtime" 10 "runtime"
(...skipping 11 matching lines...) Expand all
22 static int mygetpwuid_r(int uid, struct passwd *pwd, 22 static int mygetpwuid_r(int uid, struct passwd *pwd,
23 char *buf, size_t buflen, struct passwd **result) { 23 char *buf, size_t buflen, struct passwd **result) {
24 return getpwuid_r(uid, pwd, buf, buflen, result); 24 return getpwuid_r(uid, pwd, buf, buflen, result);
25 } 25 }
26 26
27 static int mygetgrgid_r(int gid, struct group *grp, 27 static int mygetgrgid_r(int gid, struct group *grp,
28 char *buf, size_t buflen, struct group **result) { 28 char *buf, size_t buflen, struct group **result) {
29 return getgrgid_r(gid, grp, buf, buflen, result); 29 return getgrgid_r(gid, grp, buf, buflen, result);
30 } 30 }
31 31
32 static int mygetgrouplist(const char *user, gid_t group, gid_t *groups,
33 int *ngroups) {
34 return getgrouplist(user, group, (gid_t *)groups, ngroups);
35 }
36
37 static inline gid_t group_at(int i, gid_t *groups) {
38 return groups[i];
39 }
32 static inline char **next_member(char **members) { return members + 1; } 40 static inline char **next_member(char **members) { return members + 1; }
33 */ 41 */
34 import "C" 42 import "C"
35 43
36 // Lookup looks up a user by username. If the user cannot be found, 44 // Lookup looks up a user by username. If the user cannot be found,
37 // the returned error is of type UnknownUserError. 45 // the returned error is of type UnknownUserError.
38 func Lookup(username string) (*User, os.Error) { 46 func Lookup(username string) (*User, os.Error) {
39 » return lookupUser(-1, username, true) 47 » u, err := lookupUser(username, buildUser)
48 » if err != nil {
49 » » return nil, err
50 » }
51 » return u, nil
40 } 52 }
41 53
42 // LookupId looks up a user by userid. If the user cannot be found, 54 // LookupId looks up a user by userid. If the user cannot be found,
43 // the returned error is of type UnknownUserIdError. 55 // the returned error is of type UnknownUserIdError.
44 func LookupId(uid int) (*User, os.Error) { 56 func LookupId(uid int) (*User, os.Error) {
45 » return lookupUser(uid, "", false) 57 » u, err := lookupUserId(uid, buildUser)
58 » if err != nil {
59 » » return nil, err
60 » }
61 » return u, nil
62 }
63
64 // In indicates whether the user is a member of the given group.
65 func (u *User) In(g *Group) (bool, os.Error) {
66 » if u.Gid == g.Gid {
67 » » return true, nil
68 » }
69
70 » nameC := C.CString(u.Username)
71 » defer C.free(unsafe.Pointer(nameC))
72 » groupC := C.gid_t(u.Gid)
73 » ngroupsC := C.int(0)
74
75 » C.mygetgrouplist(nameC, groupC, nil, &ngroupsC)
76 » ngroups := int(ngroupsC)
77
78 » groups := C.malloc(C.size_t(int(unsafe.Sizeof(groupC)) * ngroups))
79 » defer C.free(groups)
80
81 » rv := C.mygetgrouplist(nameC, groupC, (*C.gid_t)(groups), &ngroupsC)
82 » if rv == -1 {
83 » » return false, fmt.Errorf("user: membership of %s in %s: %s", u.U sername, g.Name, os.Errno(rv))
84 » }
85
86 » ngroups = int(ngroupsC)
87 » for i := 0; i < ngroups; i++ {
88 » » gid := C.group_at(C.int(i), (*C.gid_t)(groups))
89 » » if g.Gid == int(gid) {
90 » » » return true, nil
91 » » }
92 » }
93 » return false, nil
46 } 94 }
47 95
48 // LookupGroup looks up a group by groupname. If the group cannot 96 // LookupGroup looks up a group by groupname. If the group cannot
49 // be found, the returned error is of type UnknownGroupError. 97 // be found, the returned error is of type UnknownGroupError.
50 func LookupGroup(groupname string) (*Group, os.Error) { 98 func LookupGroup(groupname string) (*Group, os.Error) {
51 » return lookupGroup(-1, groupname, true) 99 » g, err := lookupGroup(groupname, buildGroup)
100 » if err != nil {
101 » » return nil, err
102 » }
103 » return g, nil
52 } 104 }
53 105
54 // LookupGroupId looks up a group by groupid. If the group cannot 106 // LookupGroupId looks up a group by groupid. If the group cannot
55 // be found, the returned error is of type UnknownGroupIdError. 107 // be found, the returned error is of type UnknownGroupIdError.
56 func LookupGroupId(gid int) (*Group, os.Error) { 108 func LookupGroupId(gid int) (*Group, os.Error) {
brainman 2013/03/01 00:54:33 s/int/string/
57 » return lookupGroup(gid, "", false) 109 » g, err := lookupGroupId(gid, buildGroup)
110 » if err != nil {
111 » » return nil, err
112 » }
113 » return g, nil
114 }
115
116 // Members returns the list of members of the group.
117 func (g *Group) Members() ([]string, os.Error) {
118 » var members []string
119
120 » _, err := lookupGroupId(g.Gid, func(grp *C.struct_group) *Group {
121 » » cmem := grp.gr_mem
122 » » for *cmem != nil {
123 » » » members = append(members, C.GoString(*cmem))
124 » » » cmem = C.next_member(cmem)
125 » » }
126 » » return g
127 » })
128 » if err != nil {
129 » » return nil, err
130 » }
131
132 » return members, nil
58 } 133 }
59 134
60 const ( 135 const (
61 userBuffer = iota 136 userBuffer = iota
62 groupBuffer 137 groupBuffer
63 ) 138 )
64 139
65 func lookupUser(uid int, username string, lookupByName bool) (*User, os.Error) { 140 func lookupUser(username string, f func(*C.struct_passwd) *User) (*User, os.Erro r) {
66 var pwd C.struct_passwd 141 var pwd C.struct_passwd
67 var result *C.struct_passwd 142 var result *C.struct_passwd
68 143
69 buf, bufSize, err := allocBuffer(userBuffer) 144 buf, bufSize, err := allocBuffer(userBuffer)
70 if err != nil { 145 if err != nil {
71 return nil, err 146 return nil, err
72 } 147 }
73 defer C.free(buf) 148 defer C.free(buf)
74 149
75 » var rv C.int 150 » nameC := C.CString(username)
76 » if lookupByName { 151 » defer C.free(unsafe.Pointer(nameC))
77 » » nameC := C.CString(username) 152 » rv := C.getpwnam_r(nameC,
78 » » defer C.free(unsafe.Pointer(nameC)) 153 » » &pwd,
79 » » rv = C.getpwnam_r(nameC, 154 » » (*C.char)(buf),
80 » » » &pwd, 155 » » C.size_t(bufSize),
81 » » » (*C.char)(buf), 156 » » &result)
82 » » » C.size_t(bufSize), 157 » if rv != 0 {
83 » » » &result) 158 » » return nil, fmt.Errorf("user: lookup username %s: %s", username, os.Errno(rv))
84 » » if rv != 0 { 159 » }
85 » » » return nil, fmt.Errorf("user: lookup username %s: %s", u sername, os.Errno(rv)) 160 » if result == nil {
86 » » } 161 » » return nil, UnknownUserError(username)
87 » » if result == nil { 162 » }
88 » » » return nil, UnknownUserError(username) 163 » u := f(&pwd)
89 » » } 164 » return u, nil
90 » } else { 165 }
91 » » // mygetpwuid_r is a wrapper around getpwuid_r to 166
92 » » // to avoid using uid_t because C.uid_t(uid) for 167 func lookupUserId(uid int, f func(*C.struct_passwd) *User) (*User, os.Error) {
93 » » // unknown reasons doesn't work on linux. 168 » var pwd C.struct_passwd
94 » » rv = C.mygetpwuid_r(C.int(uid), 169 » var result *C.struct_passwd
95 » » » &pwd, 170
96 » » » (*C.char)(buf), 171 » buf, bufSize, err := allocBuffer(userBuffer)
97 » » » C.size_t(bufSize), 172 » if err != nil {
98 » » » &result) 173 » » return nil, err
99 » » if rv != 0 { 174 » }
100 » » » return nil, fmt.Errorf("user: lookup userid %d: %s", uid , os.Errno(rv)) 175 » defer C.free(buf)
101 » » } 176
102 » » if result == nil { 177 » // mygetpwuid_r is a wrapper around getpwuid_r to
103 » » » return nil, UnknownUserIdError(uid) 178 » // to avoid using uid_t because C.uid_t(uid) for
104 » » } 179 » // unknown reasons doesn't work on linux.
105 » } 180 » rv := C.mygetpwuid_r(C.int(uid),
181 » » &pwd,
182 » » (*C.char)(buf),
183 » » C.size_t(bufSize),
184 » » &result)
185 » if rv != 0 {
186 » » return nil, fmt.Errorf("user: lookup userid %d: %s", uid, os.Err no(rv))
187 » }
188 » if result == nil {
189 » » return nil, UnknownUserIdError(uid)
190 » }
191 » u := f(&pwd)
192 » return u, nil
193 }
194
195 func buildUser(pwd *C.struct_passwd) *User {
106 u := &User{ 196 u := &User{
107 Uid: int(pwd.pw_uid), 197 Uid: int(pwd.pw_uid),
108 Gid: int(pwd.pw_gid), 198 Gid: int(pwd.pw_gid),
109 Username: C.GoString(pwd.pw_name), 199 Username: C.GoString(pwd.pw_name),
110 Name: C.GoString(pwd.pw_gecos), 200 Name: C.GoString(pwd.pw_gecos),
111 HomeDir: C.GoString(pwd.pw_dir), 201 HomeDir: C.GoString(pwd.pw_dir),
112 } 202 }
113 // The pw_gecos field isn't quite standardized. Some docs 203 // The pw_gecos field isn't quite standardized. Some docs
114 // say: "It is expected to be a comma separated list of 204 // say: "It is expected to be a comma separated list of
115 // personal data where the first item is the full name of the 205 // personal data where the first item is the full name of the
116 // user." 206 // user."
117 if i := strings.Index(u.Name, ","); i >= 0 { 207 if i := strings.Index(u.Name, ","); i >= 0 {
118 u.Name = u.Name[:i] 208 u.Name = u.Name[:i]
119 } 209 }
120 » return u, nil 210 » return u
121 } 211 }
122 212
123 func lookupGroup(gid int, groupname string, lookupByName bool) (*Group, os.Error ) { 213 func lookupGroup(groupname string, f func(*C.struct_group) *Group) (*Group, os.E rror) {
124 var grp C.struct_group 214 var grp C.struct_group
125 var result *C.struct_group 215 var result *C.struct_group
126 216
127 buf, bufSize, err := allocBuffer(groupBuffer) 217 buf, bufSize, err := allocBuffer(groupBuffer)
128 if err != nil { 218 if err != nil {
129 return nil, err 219 return nil, err
130 } 220 }
131 defer C.free(buf) 221 defer C.free(buf)
132 222
133 » var rv C.int 223 » nameC := C.CString(groupname)
134 » if lookupByName { 224 » defer C.free(unsafe.Pointer(nameC))
135 » » nameC := C.CString(groupname) 225 » rv := C.getgrnam_r(nameC,
136 » » defer C.free(unsafe.Pointer(nameC)) 226 » » &grp,
137 » » rv = C.getgrnam_r(nameC, 227 » » (*C.char)(buf),
138 » » » &grp, 228 » » C.size_t(bufSize),
139 » » » (*C.char)(buf), 229 » » &result)
140 » » » C.size_t(bufSize), 230 » if rv != 0 {
141 » » » &result) 231 » » return nil, fmt.Errorf("group: lookup groupname %s: %s", groupna me, os.Errno(rv))
142 » » if rv != 0 { 232 » }
143 » » » return nil, fmt.Errorf("group: lookup groupname %s: %s", groupname, os.Errno(rv)) 233 » if result == nil {
144 » » } 234 » » return nil, UnknownGroupError(groupname)
145 » » if result == nil { 235 » }
146 » » » return nil, UnknownGroupError(groupname) 236 » g := f(&grp)
147 » » } 237 » return g, nil
148 » } else { 238 }
149 » » // mygetgrgid_r is a wrapper around getgrgid_r to 239
150 » » // to avoid using gid_t because C.gid_t(gid) for 240 func lookupGroupId(gid int, f func(*C.struct_group) *Group) (*Group, os.Error) {
151 » » // unknown reasons doesn't work on linux. 241 » var grp C.struct_group
152 » » rv = C.mygetgrgid_r(C.int(gid), 242 » var result *C.struct_group
153 » » » &grp, 243
154 » » » (*C.char)(buf), 244 » buf, bufSize, err := allocBuffer(groupBuffer)
155 » » » C.size_t(bufSize), 245 » if err != nil {
156 » » » &result) 246 » » return nil, err
157 » » if rv != 0 { 247 » }
158 » » » return nil, fmt.Errorf("group: lookup groupid %d: %s", g id, os.Errno(rv)) 248 » defer C.free(buf)
159 » » } 249
160 » » if result == nil { 250 » // mygetgrgid_r is a wrapper around getgrgid_r to
161 » » » return nil, UnknownGroupIdError(gid) 251 » // to avoid using gid_t because C.gid_t(gid) for
162 » » } 252 » // unknown reasons doesn't work on linux.
163 » } 253 » rv := C.mygetgrgid_r(C.int(gid),
164 254 » » &grp,
165 » var members []string 255 » » (*C.char)(buf),
166 » cmem := grp.gr_mem 256 » » C.size_t(bufSize),
167 » for *cmem != nil { 257 » » &result)
168 » » members = append(members, C.GoString(*cmem)) 258 » if rv != 0 {
169 » » cmem = C.next_member(cmem) 259 » » return nil, fmt.Errorf("group: lookup groupid %d: %s", gid, os.E rrno(rv))
170 » } 260 » }
171 261 » if result == nil {
262 » » return nil, UnknownGroupIdError(gid)
263 » }
264 » g := f(&grp)
265 » return g, nil
266 }
267
268 func buildGroup(grp *C.struct_group) *Group {
172 g := &Group{ 269 g := &Group{
173 » » Gid: int(grp.gr_gid), 270 » » Gid: int(grp.gr_gid),
174 » » Groupname: C.GoString(grp.gr_name), 271 » » Name: C.GoString(grp.gr_name),
175 » » Members: members, 272 » }
176 » } 273 » return g
177 » return g, nil
178 } 274 }
179 275
180 func allocBuffer(bufType int) (unsafe.Pointer, C.long, os.Error) { 276 func allocBuffer(bufType int) (unsafe.Pointer, C.long, os.Error) {
181 var bufSize C.long 277 var bufSize C.long
182 if runtime.GOOS == "freebsd" { 278 if runtime.GOOS == "freebsd" {
183 // FreeBSD doesn't have _SC_GETPW_R_SIZE_MAX 279 // FreeBSD doesn't have _SC_GETPW_R_SIZE_MAX
184 // or SC_GETGR_R_SIZE_MAX and just returns -1. 280 // or SC_GETGR_R_SIZE_MAX and just returns -1.
185 // So just use the same size that Linux returns 281 // So just use the same size that Linux returns
186 bufSize = 1024 282 bufSize = 1024
187 } else { 283 } else {
188 var size C.int 284 var size C.int
189 var constName string 285 var constName string
190 switch bufType { 286 switch bufType {
191 case userBuffer: 287 case userBuffer:
192 size = C._SC_GETPW_R_SIZE_MAX 288 size = C._SC_GETPW_R_SIZE_MAX
193 constName = "_SC_GETPW_R_SIZE_MAX" 289 constName = "_SC_GETPW_R_SIZE_MAX"
194 case groupBuffer: 290 case groupBuffer:
195 size = C._SC_GETGR_R_SIZE_MAX 291 size = C._SC_GETGR_R_SIZE_MAX
196 constName = "_SC_GETGR_R_SIZE_MAX" 292 constName = "_SC_GETGR_R_SIZE_MAX"
197 } 293 }
198 bufSize = C.sysconf(size) 294 bufSize = C.sysconf(size)
199 if bufSize <= 0 || bufSize > 1<<20 { 295 if bufSize <= 0 || bufSize > 1<<20 {
200 return nil, bufSize, fmt.Errorf("user: unreasonable %s o f %d", constName, bufSize) 296 return nil, bufSize, fmt.Errorf("user: unreasonable %s o f %d", constName, bufSize)
201 } 297 }
202 } 298 }
203 return C.malloc(C.size_t(bufSize)), bufSize, nil 299 return C.malloc(C.size_t(bufSize)), bufSize, nil
204 } 300 }
LEFTRIGHT

Powered by Google App Engine
RSS Feeds Recent Issues | This issue
This is Rietveld f62528b