rewrite initgroups_dyn

This commit is contained in:
Motiejus Jakštys 2022-07-15 10:32:45 +03:00
parent 4aee66fb11
commit 7960cf25c9

View File

@ -481,18 +481,26 @@ fn initgroups_dyn(
// TODO: use db.userGids() // TODO: use db.userGids()
const offset = user.additional_gids_offset; const offset = user.additional_gids_offset;
var vit = compress.varintSliceIteratorMust(db.additional_gids[offset..]); var vit = compress.varintSliceIteratorMust(db.additional_gids[offset..]);
const remaining = vit.remaining;
var gids = compress.deltaDecompressionIterator(&vit); var gids = compress.deltaDecompressionIterator(&vit);
if (size.* < remaining) {
// the implementation below is ported from glibc's db-initgroups.c
// even though we know the size of the groups upfront, I found it too difficult
// to preallocate and juggle size, start and limit while keeping glibc happy.
var any: bool = false;
while (gids.nextMust()) |gid| {
if (start.* == size.*) {
if (limit > 0 and size.* == limit)
return c.NSS_STATUS_SUCCESS;
const oldsize = @intCast(usize, size.*); const oldsize = @intCast(usize, size.*);
const newsize = if (limit <= 0) const newsize: usize = if (limit <= 0)
oldsize + gids.remaining() 2 * oldsize
else else
math.min(@intCast(usize, limit), oldsize + gids.remaining()); math.min(@intCast(usize, limit), 2 * oldsize);
var buf = groupsp.*[0..oldsize]; var buf = groupsp.*[0..oldsize];
const new_groups = state.initgroups_dyn_allocator.realloc(buf, newsize); const new_groups = state.initgroups_dyn_allocator.realloc(buf, newsize);
if (new_groups) |newgroups| { if (new_groups) |newgroups| {
groupsp.* = newgroups.ptr; groupsp.* = newgroups.ptr;
size.* = @intCast(c_long, newsize); size.* = @intCast(c_long, newsize);
@ -504,23 +512,12 @@ fn initgroups_dyn(
} }
} }
// I was not able to understand the expected behavior of limit. In glibc any = true;
// compat-initgroups.c limit is used to malloc the buffer. Something like
// this is all over the place:
// if (limit > 0 && *size == limit) /* We reached the maximum. */
// return;
// Our implementation will thus limit the number of *added* entries.
var added: usize = 0;
while (gids.nextMust()) |gid| {
if (limit > 0 and added == limit) break;
added += 1;
groupsp.*[@intCast(usize, start.*)] = @intCast(u32, gid); groupsp.*[@intCast(usize, start.*)] = @intCast(u32, gid);
start.* += 1; start.* += 1;
} }
return if (added > 0) c.NSS_STATUS_SUCCESS else c.NSS_STATUS_NOTFOUND; return if (any) c.NSS_STATUS_SUCCESS else c.NSS_STATUS_NOTFOUND;
} }
fn getDBErrno(errnop: *c_int) ?*const DB { fn getDBErrno(errnop: *c_int) ?*const DB {