1
Fork 0

rewrite initgroups_dyn

main
Motiejus Jakštys 2022-07-15 10:32:45 +03:00
parent 4aee66fb11
commit 7960cf25c9
1 changed files with 29 additions and 32 deletions

View File

@ -481,46 +481,43 @@ fn initgroups_dyn(
// TODO: use db.userGids()
const offset = user.additional_gids_offset;
var vit = compress.varintSliceIteratorMust(db.additional_gids[offset..]);
const remaining = vit.remaining;
var gids = compress.deltaDecompressionIterator(&vit);
if (size.* < remaining) {
const oldsize = @intCast(usize, size.*);
const newsize = if (limit <= 0)
oldsize + gids.remaining()
else
math.min(@intCast(usize, limit), oldsize + gids.remaining());
var buf = groupsp.*[0..oldsize];
const new_groups = state.initgroups_dyn_allocator.realloc(buf, newsize);
if (new_groups) |newgroups| {
groupsp.* = newgroups.ptr;
size.* = @intCast(c_long, newsize);
} else |err| switch (err) {
error.OutOfMemory => {
errnop.* = @enumToInt(os.E.NOMEM);
return c.NSS_STATUS_TRYAGAIN;
},
}
}
// I was not able to understand the expected behavior of limit. In glibc
// 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;
// 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 (limit > 0 and added == limit) break;
if (start.* == size.*) {
if (limit > 0 and size.* == limit)
return c.NSS_STATUS_SUCCESS;
added += 1;
const oldsize = @intCast(usize, size.*);
const newsize: usize = if (limit <= 0)
2 * oldsize
else
math.min(@intCast(usize, limit), 2 * oldsize);
var buf = groupsp.*[0..oldsize];
const new_groups = state.initgroups_dyn_allocator.realloc(buf, newsize);
if (new_groups) |newgroups| {
groupsp.* = newgroups.ptr;
size.* = @intCast(c_long, newsize);
} else |err| switch (err) {
error.OutOfMemory => {
errnop.* = @enumToInt(os.E.NOMEM);
return c.NSS_STATUS_TRYAGAIN;
},
}
}
any = true;
groupsp.*[@intCast(usize, start.*)] = @intCast(u32, gid);
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 {