-
Notifications
You must be signed in to change notification settings - Fork 683
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add getpwnam
and related functions
#864
Changes from 3 commits
0846f15
072c08d
16f3cf5
a8143fb
de1ed63
51d39cf
3b75439
b3d7716
b361db0
76e33fe
5eda92f
d0b23f3
56b0cd1
cc9f81c
65ba0e5
9111d12
3fe2c01
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -30,7 +30,7 @@ pub use self::usergroupiter::*; | |
/// | ||
/// Newtype pattern around `uid_t` (which is just alias). It prevents bugs caused by accidentally | ||
/// passing wrong value. | ||
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash, Default)] | ||
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] | ||
pub struct Uid(uid_t); | ||
|
||
impl Uid { | ||
|
@@ -79,7 +79,7 @@ pub const ROOT: Uid = Uid(0); | |
/// | ||
/// Newtype pattern around `gid_t` (which is just alias). It prevents bugs caused by accidentally | ||
/// passing wrong value. | ||
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash, Default)] | ||
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] | ||
pub struct Gid(gid_t); | ||
|
||
impl Gid { | ||
|
@@ -1336,32 +1336,34 @@ pub fn setgid(gid: Gid) -> Result<()> { | |
#[cfg(not(any(target_os = "ios", target_os = "macos")))] | ||
pub fn getgroups() -> Result<Vec<Gid>> { | ||
// First get the number of groups so we can size our Vec | ||
let ret = unsafe { libc::getgroups(0, ptr::null_mut()) }; | ||
let ngroups = unsafe { libc::getgroups(0, ptr::null_mut()) }; | ||
let ngroups_max = match sysconf(SysconfVar::NGROUPS_MAX) { | ||
Ok(Some(n)) => n as usize, | ||
Ok(None) | Err(_) => <usize>::max_value(), | ||
}; | ||
|
||
// Now actually get the groups. We try multiple times in case the number of | ||
// groups has changed since the first call to getgroups() and the buffer is | ||
// now too small. | ||
let mut groups = Vec::<Gid>::with_capacity(Errno::result(ret)? as usize); | ||
let mut groups = Vec::<Gid>::with_capacity(Errno::result(ngroups)? as usize); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think the code would be more readable if you moved There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Reworked. Also, the 16Kb was taken from https://linux.die.net/man/3/getpwuid_r example code. |
||
loop { | ||
// FIXME: On the platforms we currently support, the `Gid` struct has | ||
// the same representation in memory as a bare `gid_t`. This is not | ||
// necessarily the case on all Rust platforms, though. See RFC 1785. | ||
let ret = unsafe { | ||
let ngroups = unsafe { | ||
libc::getgroups(groups.capacity() as c_int, groups.as_mut_ptr() as *mut gid_t) | ||
}; | ||
|
||
match Errno::result(ret) { | ||
match Errno::result(ngroups) { | ||
Ok(s) => { | ||
unsafe { groups.set_len(s as usize) }; | ||
return Ok(groups); | ||
}, | ||
Err(Error::Sys(Errno::EINVAL)) => { | ||
// EINVAL indicates that the buffer size was too small. Trigger | ||
// the internal buffer resizing logic of `Vec` by requiring | ||
// more space than the current capacity. | ||
let cap = groups.capacity(); | ||
unsafe { groups.set_len(cap) }; | ||
groups.reserve(1); | ||
// EINVAL indicates that the buffer size was too | ||
// small. Trigger the internal buffer resizing logic | ||
reserve_double_buffer_size(&mut groups, ngroups_max) | ||
.or(Err(Error::Sys(Errno::EINVAL)))?; | ||
}, | ||
Err(e) => return Err(e) | ||
} | ||
|
@@ -1479,19 +1481,8 @@ pub fn getgrouplist(user: &CStr, group: Gid) -> Result<Vec<Gid>> { | |
// BSD systems will still fill the groups buffer with as many | ||
// groups as possible, but Linux manpages do not mention this | ||
// behavior. | ||
|
||
let cap = groups.capacity(); | ||
if cap >= ngroups_max as usize { | ||
// We already have the largest capacity we can, give up | ||
return Err(Error::invalid_argument()); | ||
} | ||
|
||
// Reserve space for at least ngroups | ||
groups.reserve(ngroups as usize); | ||
|
||
// Even if the buffer gets resized to bigger than ngroups_max, | ||
// don't ever ask for more than ngroups_max groups | ||
ngroups = min(ngroups_max, groups.capacity() as c_int); | ||
reserve_double_buffer_size(&mut groups, ngroups_max as usize) | ||
.or(Err(Error::invalid_argument()))?; | ||
} | ||
} | ||
} | ||
|
@@ -2423,7 +2414,7 @@ const PWGRP_BUFSIZE: usize = 1024; | |
/// fields are based on the user's locale, which could be non-UTF8, while other fields are | ||
/// guaranteed to conform to [`NAME_REGEX`](https://serverfault.com/a/73101/407341), which only | ||
/// contains ASCII. | ||
#[derive(Debug, Clone, PartialEq, Default)] | ||
#[derive(Debug, Clone, PartialEq)] | ||
pub struct User { | ||
/// Username | ||
pub name: String, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why make some fields There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Because it's guaranteed that the fields I made There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ahh, makes sense. Could you add a comment to that effect? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this seems done as well since d4d5a00. |
||
|
@@ -2482,9 +2473,10 @@ impl User { | |
libc::size_t, | ||
*mut *mut libc::passwd) -> libc::c_int | ||
{ | ||
let buflimit = 16384; | ||
let bufsize = match sysconf(SysconfVar::GETPW_R_SIZE_MAX) { | ||
Ok(Some(n)) => n as usize, | ||
Ok(None) | Err(_) => 1024 as usize, | ||
Ok(None) | Err(_) => buflimit as usize, | ||
}; | ||
|
||
let mut cbuf = Vec::with_capacity(bufsize); | ||
|
@@ -2506,7 +2498,7 @@ impl User { | |
} | ||
} else if Errno::last() == Errno::ERANGE { | ||
// Trigger the internal buffer resizing logic. | ||
reserve_double_buffer_size(&mut cbuf, bufsize)?; | ||
reserve_double_buffer_size(&mut cbuf, buflimit)?; | ||
} else { | ||
return Err(Error::Sys(Errno::last())); | ||
} | ||
|
@@ -2600,9 +2592,10 @@ impl Group { | |
libc::size_t, | ||
*mut *mut libc::group) -> libc::c_int | ||
{ | ||
let buflimit = 16384; | ||
let bufsize = match sysconf(SysconfVar::GETGR_R_SIZE_MAX) { | ||
Ok(Some(n)) => n as usize, | ||
Ok(None) | Err(_) => 1024 as usize, | ||
Ok(None) | Err(_) => buflimit as usize, | ||
}; | ||
|
||
let mut cbuf = Vec::with_capacity(bufsize); | ||
|
@@ -2624,7 +2617,7 @@ impl Group { | |
} | ||
} else if Errno::last() == Errno::ERANGE { | ||
// Trigger the internal buffer resizing logic. | ||
reserve_double_buffer_size(&mut cbuf, bufsize)?; | ||
reserve_double_buffer_size(&mut cbuf, buflimit)?; | ||
} else { | ||
return Err(Error::Sys(Errno::last())); | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What I meant is that it would be more idiomatic to write it like this: