diff options
Diffstat (limited to 'go/golang/gocache/66/66fc8816e54b731ce80418edca379a32d7c7d17de1cc960a413b621623aee3ea-d')
-rw-r--r-- | go/golang/gocache/66/66fc8816e54b731ce80418edca379a32d7c7d17de1cc960a413b621623aee3ea-d | 282 |
1 files changed, 282 insertions, 0 deletions
diff --git a/go/golang/gocache/66/66fc8816e54b731ce80418edca379a32d7c7d17de1cc960a413b621623aee3ea-d b/go/golang/gocache/66/66fc8816e54b731ce80418edca379a32d7c7d17de1cc960a413b621623aee3ea-d new file mode 100644 index 00000000..4904bc02 --- /dev/null +++ b/go/golang/gocache/66/66fc8816e54b731ce80418edca379a32d7c7d17de1cc960a413b621623aee3ea-d @@ -0,0 +1,282 @@ +// Code generated by cmd/cgo; DO NOT EDIT. + +//line /workdir/go/src/os/user/cgo_lookup_unix.go:1:1 +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build darwin dragonfly freebsd !android,linux netbsd openbsd solaris +// +build cgo,!osusergo + +package user; import _cgo_unsafe "unsafe" + +import ( + "fmt" + "strconv" + "strings" + "syscall" + "unsafe" +) + +/* +#cgo solaris CFLAGS: -D_POSIX_PTHREAD_SEMANTICS +#include <unistd.h> +#include <sys/types.h> +#include <pwd.h> +#include <grp.h> +#include <stdlib.h> + +static int mygetpwuid_r(int uid, struct passwd *pwd, + char *buf, size_t buflen, struct passwd **result) { + return getpwuid_r(uid, pwd, buf, buflen, result); +} + +static int mygetpwnam_r(const char *name, struct passwd *pwd, + char *buf, size_t buflen, struct passwd **result) { + return getpwnam_r(name, pwd, buf, buflen, result); +} + +static int mygetgrgid_r(int gid, struct group *grp, + char *buf, size_t buflen, struct group **result) { + return getgrgid_r(gid, grp, buf, buflen, result); +} + +static int mygetgrnam_r(const char *name, struct group *grp, + char *buf, size_t buflen, struct group **result) { + return getgrnam_r(name, grp, buf, buflen, result); +} +*/ +import _ "unsafe" + +func current() (*User, error) { + return lookupUnixUid(syscall.Getuid()) +} + +func lookupUser(username string) (*User, error) { + var pwd _Ctype_struct_passwd + var result *_Ctype_struct_passwd + nameC := make([]byte, len(username)+1) + copy(nameC, username) + + buf := alloc(userBuffer) + defer buf.free() + + err := retryWithBuffer(buf, func() syscall.Errno { + // mygetpwnam_r is a wrapper around getpwnam_r to avoid + // passing a size_t to getpwnam_r, because for unknown + // reasons passing a size_t to getpwnam_r doesn't work on + // Solaris. + return syscall.Errno(func(_cgo0 *_Ctype_char, _cgo1 *_Ctype_struct_passwd, _cgo2 *_Ctype_char, _cgo3 _Ctype_size_t, _cgo4 **_Ctype_struct_passwd) _Ctype_int {; _cgoCheckPointer(_cgo1, true); _cgoCheckPointer(_cgo4, true); return (_Cfunc_mygetpwnam_r)(_cgo0, _cgo1, _cgo2, _cgo3, _cgo4);}((*_Ctype_char)(unsafe.Pointer(&nameC[0])), + &pwd, + (*_Ctype_char)(buf.ptr), + _Ctype_size_t(buf.size), + &result)) + }) + if err != nil { + return nil, fmt.Errorf("user: lookup username %s: %v", username, err) + } + if result == nil { + return nil, UnknownUserError(username) + } + return buildUser(&pwd), err +} + +func lookupUserId(uid string) (*User, error) { + i, e := strconv.Atoi(uid) + if e != nil { + return nil, e + } + return lookupUnixUid(i) +} + +func lookupUnixUid(uid int) (*User, error) { + var pwd _Ctype_struct_passwd + var result *_Ctype_struct_passwd + + buf := alloc(userBuffer) + defer buf.free() + + err := retryWithBuffer(buf, func() syscall.Errno { + // mygetpwuid_r is a wrapper around getpwuid_r to + // to avoid using uid_t because C.uid_t(uid) for + // unknown reasons doesn't work on linux. + return syscall.Errno(func(_cgo0 _Ctype_int, _cgo1 *_Ctype_struct_passwd, _cgo2 *_Ctype_char, _cgo3 _Ctype_size_t, _cgo4 **_Ctype_struct_passwd) _Ctype_int {; _cgoCheckPointer(_cgo1, true); _cgoCheckPointer(_cgo4, true); return (_Cfunc_mygetpwuid_r)(_cgo0, _cgo1, _cgo2, _cgo3, _cgo4);}(_Ctype_int(uid), + &pwd, + (*_Ctype_char)(buf.ptr), + _Ctype_size_t(buf.size), + &result)) + }) + if err != nil { + return nil, fmt.Errorf("user: lookup userid %d: %v", uid, err) + } + if result == nil { + return nil, UnknownUserIdError(uid) + } + return buildUser(&pwd), nil +} + +func buildUser(pwd *_Ctype_struct_passwd) *User { + u := &User{ + Uid: strconv.FormatUint(uint64(pwd.pw_uid), 10), + Gid: strconv.FormatUint(uint64(pwd.pw_gid), 10), + Username: (_Cfunc_GoString)(pwd.pw_name), + Name: (_Cfunc_GoString)(pwd.pw_gecos), + HomeDir: (_Cfunc_GoString)(pwd.pw_dir), + } + // The pw_gecos field isn't quite standardized. Some docs + // say: "It is expected to be a comma separated list of + // personal data where the first item is the full name of the + // user." + if i := strings.Index(u.Name, ","); i >= 0 { + u.Name = u.Name[:i] + } + return u +} + +func currentGroup() (*Group, error) { + return lookupUnixGid(syscall.Getgid()) +} + +func lookupGroup(groupname string) (*Group, error) { + var grp _Ctype_struct_group + var result *_Ctype_struct_group + + buf := alloc(groupBuffer) + defer buf.free() + cname := make([]byte, len(groupname)+1) + copy(cname, groupname) + + err := retryWithBuffer(buf, func() syscall.Errno { + return syscall.Errno(func(_cgo0 *_Ctype_char, _cgo1 *_Ctype_struct_group, _cgo2 *_Ctype_char, _cgo3 _Ctype_size_t, _cgo4 **_Ctype_struct_group) _Ctype_int {; _cgoCheckPointer(_cgo1, true); _cgoCheckPointer(_cgo4, true); return (_Cfunc_mygetgrnam_r)(_cgo0, _cgo1, _cgo2, _cgo3, _cgo4);}((*_Ctype_char)(unsafe.Pointer(&cname[0])), + &grp, + (*_Ctype_char)(buf.ptr), + _Ctype_size_t(buf.size), + &result)) + }) + if err != nil { + return nil, fmt.Errorf("user: lookup groupname %s: %v", groupname, err) + } + if result == nil { + return nil, UnknownGroupError(groupname) + } + return buildGroup(&grp), nil +} + +func lookupGroupId(gid string) (*Group, error) { + i, e := strconv.Atoi(gid) + if e != nil { + return nil, e + } + return lookupUnixGid(i) +} + +func lookupUnixGid(gid int) (*Group, error) { + var grp _Ctype_struct_group + var result *_Ctype_struct_group + + buf := alloc(groupBuffer) + defer buf.free() + + err := retryWithBuffer(buf, func() syscall.Errno { + // mygetgrgid_r is a wrapper around getgrgid_r to + // to avoid using gid_t because C.gid_t(gid) for + // unknown reasons doesn't work on linux. + return syscall.Errno(func(_cgo0 _Ctype_int, _cgo1 *_Ctype_struct_group, _cgo2 *_Ctype_char, _cgo3 _Ctype_size_t, _cgo4 **_Ctype_struct_group) _Ctype_int {; _cgoCheckPointer(_cgo1, true); _cgoCheckPointer(_cgo4, true); return (_Cfunc_mygetgrgid_r)(_cgo0, _cgo1, _cgo2, _cgo3, _cgo4);}(_Ctype_int(gid), + &grp, + (*_Ctype_char)(buf.ptr), + _Ctype_size_t(buf.size), + &result)) + }) + if err != nil { + return nil, fmt.Errorf("user: lookup groupid %d: %v", gid, err) + } + if result == nil { + return nil, UnknownGroupIdError(strconv.Itoa(gid)) + } + return buildGroup(&grp), nil +} + +func buildGroup(grp *_Ctype_struct_group) *Group { + g := &Group{ + Gid: strconv.Itoa(int(grp.gr_gid)), + Name: (_Cfunc_GoString)(grp.gr_name), + } + return g +} + +type bufferKind _Ctype_int + +const ( + userBuffer = bufferKind((_Ciconst__SC_GETPW_R_SIZE_MAX)) + groupBuffer = bufferKind((_Ciconst__SC_GETGR_R_SIZE_MAX)) +) + +func (k bufferKind) initialSize() _Ctype_size_t { + sz := (_Cfunc_sysconf)(_Ctype_int(k)) + if sz == -1 { + // DragonFly and FreeBSD do not have _SC_GETPW_R_SIZE_MAX. + // Additionally, not all Linux systems have it, either. For + // example, the musl libc returns -1. + return 1024 + } + if !isSizeReasonable(int64(sz)) { + // Truncate. If this truly isn't enough, retryWithBuffer will error on the first run. + return maxBufferSize + } + return _Ctype_size_t(sz) +} + +type memBuffer struct { + ptr unsafe.Pointer + size _Ctype_size_t +} + +func alloc(kind bufferKind) *memBuffer { + sz := kind.initialSize() + return &memBuffer{ + ptr: (_Cfunc__CMalloc)(sz), + size: sz, + } +} + +func (mb *memBuffer) resize(newSize _Ctype_size_t) { + mb.ptr = func(_cgo0 _cgo_unsafe.Pointer, _cgo1 _Ctype_size_t) _cgo_unsafe.Pointer {; _cgoCheckPointer(_cgo0); return (_Cfunc_realloc)(_cgo0, _cgo1);}(mb.ptr, newSize) + mb.size = newSize +} + +func (mb *memBuffer) free() { + func(_cgo0 _cgo_unsafe.Pointer) {; _cgoCheckPointer(_cgo0); (_Cfunc_free)(_cgo0);}(mb.ptr) +} + +// retryWithBuffer repeatedly calls f(), increasing the size of the +// buffer each time, until f succeeds, fails with a non-ERANGE error, +// or the buffer exceeds a reasonable limit. +func retryWithBuffer(buf *memBuffer, f func() syscall.Errno) error { + for { + errno := f() + if errno == 0 { + return nil + } else if errno != syscall.ERANGE { + return errno + } + newSize := buf.size * 2 + if !isSizeReasonable(int64(newSize)) { + return fmt.Errorf("internal buffer exceeds %d bytes", maxBufferSize) + } + buf.resize(newSize) + } +} + +const maxBufferSize = 1 << 20 + +func isSizeReasonable(sz int64) bool { + return sz > 0 && sz <= maxBufferSize +} + +// Because we can't use cgo in tests: +func structPasswdForNegativeTest() _Ctype_struct_passwd { + sp := _Ctype_struct_passwd{} + sp.pw_uid = 1<<32 - 2 + sp.pw_gid = 1<<32 - 3 + return sp +} |