func getUserName(fi os.FileInfo) (string, error) { var rv C.int var pwd C.struct_passwd var pwdres *C.struct_passwd var bufSize C.long var result string bufSize = 1024 buf := C.malloc(C.size_t(bufSize)) defer C.free(buf) uid := fi.Sys().(*syscall.Stat_t).Uid rv = C.mygetpwuid_r(C.int(uid), &pwd, (*C.char)(buf), C.size_t(bufSize), &pwdres) if rv != 0 { return "", errors.New("Could not read username") } if pwdres != nil { result = C.GoString(pwd.pw_name) } else { return "", errors.New("Could not convert username") } return result, nil }
func lookupUnixUid(uid int) (*User, error) { var pwd C.struct_passwd var result *C.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(C.mygetpwuid_r(C.int(uid), &pwd, (*C.char)(buf.ptr), C.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 lookup(uid int, username string, lookupByName bool) (*User, error) { var pwd C.struct_passwd var result *C.struct_passwd var bufSize C.long if runtime.GOOS == "freebsd" { // FreeBSD doesn't have _SC_GETPW_R_SIZE_MAX // and just returns -1. So just use the same // size that Linux returns bufSize = 1024 } else { bufSize = C.sysconf(C._SC_GETPW_R_SIZE_MAX) if bufSize <= 0 || bufSize > 1<<20 { return nil, fmt.Errorf("user: unreasonable _SC_GETPW_R_SIZE_MAX of %d", bufSize) } } buf := C.malloc(C.size_t(bufSize)) defer C.free(buf) var rv C.int if lookupByName { nameC := C.CString(username) defer C.free(unsafe.Pointer(nameC)) rv = C.getpwnam_r(nameC, &pwd, (*C.char)(buf), C.size_t(bufSize), &result) if rv != 0 { return nil, fmt.Errorf("user: lookup username %s: %s", username, syscall.Errno(rv)) } if result == nil { return nil, UnknownUserError(username) } } else { // 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. rv = C.mygetpwuid_r(C.int(uid), &pwd, (*C.char)(buf), C.size_t(bufSize), &result) if rv != 0 { return nil, fmt.Errorf("user: lookup userid %d: %s", uid, syscall.Errno(rv)) } if result == nil { return nil, UnknownUserIdError(uid) } } u := &User{ Uid: strconv.Itoa(int(pwd.pw_uid)), Gid: strconv.Itoa(int(pwd.pw_gid)), Username: C.GoString(pwd.pw_name), Name: C.GoString(pwd.pw_gecos), HomeDir: C.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, nil }
func lookupUnix(uid int, username string, lookupByName bool) (*User, error) { var pwd C.struct_passwd var result *C.struct_passwd bufSize := C.sysconf(C._SC_GETPW_R_SIZE_MAX) if bufSize == -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. bufSize = 1024 } if bufSize <= 0 || bufSize > 1<<20 { return nil, fmt.Errorf("user: unreasonable _SC_GETPW_R_SIZE_MAX of %d", bufSize) } buf := C.malloc(C.size_t(bufSize)) defer C.free(buf) var rv C.int if lookupByName { nameC := C.CString(username) defer C.free(unsafe.Pointer(nameC)) // 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. rv = C.mygetpwnam_r(nameC, &pwd, (*C.char)(buf), C.size_t(bufSize), &result) if rv != 0 { return nil, fmt.Errorf("user: lookup username %s: %s", username, syscall.Errno(rv)) } if result == nil { return nil, UnknownUserError(username) } } else { // 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. rv = C.mygetpwuid_r(C.int(uid), &pwd, (*C.char)(buf), C.size_t(bufSize), &result) if rv != 0 { return nil, fmt.Errorf("user: lookup userid %d: %s", uid, syscall.Errno(rv)) } if result == nil { return nil, UnknownUserIdError(uid) } } u := &User{ Uid: strconv.Itoa(int(pwd.pw_uid)), Gid: strconv.Itoa(int(pwd.pw_gid)), Username: C.GoString(pwd.pw_name), Name: C.GoString(pwd.pw_gecos), HomeDir: C.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, nil }