1
Fork 0
mirror of https://github.com/RGBCube/uutils-coreutils synced 2025-07-29 12:07:46 +00:00

getgroups: Handle race conditions properly

This commit is contained in:
Jan Verbeek 2021-09-12 13:12:28 +02:00
parent 412a81e7bf
commit b125159535

View file

@ -72,19 +72,28 @@ extern "C" {
/// > to be used in a further call to getgroups(). /// > to be used in a further call to getgroups().
#[cfg(not(target_os = "redox"))] #[cfg(not(target_os = "redox"))]
pub fn get_groups() -> IOResult<Vec<gid_t>> { pub fn get_groups() -> IOResult<Vec<gid_t>> {
let ngroups = unsafe { getgroups(0, ptr::null_mut()) }; loop {
if ngroups == -1 { let ngroups = match unsafe { getgroups(0, ptr::null_mut()) } {
return Err(IOError::last_os_error()); -1 => return Err(IOError::last_os_error()),
} // Not just optimization; 0 would mess up the next call
let mut groups = vec![0; ngroups.try_into().unwrap()]; 0 => return Ok(Vec::new()),
let ngroups = unsafe { getgroups(ngroups, groups.as_mut_ptr()) }; n => n,
if ngroups == -1 { };
Err(IOError::last_os_error())
} else { let mut groups = vec![0; ngroups.try_into().unwrap()];
let ngroups = ngroups.try_into().unwrap(); let res = unsafe { getgroups(ngroups, groups.as_mut_ptr()) };
assert!(ngroups <= groups.len()); if res == -1 {
groups.truncate(ngroups); let err = IOError::last_os_error();
Ok(groups) if err.raw_os_error() == Some(libc::EINVAL) {
// Number of groups changed, retry
continue;
} else {
return Err(err);
}
} else {
groups.truncate(ngroups.try_into().unwrap());
return Ok(groups);
}
} }
} }