use omit_members sometimes

This commit is contained in:
Motiejus Jakštys 2022-07-08 08:40:24 +03:00
parent 434f9e1571
commit 5fa4a71ddf
2 changed files with 76 additions and 20 deletions

View File

@ -279,6 +279,28 @@ pub fn fromBytes(buf: []align(8) const u8) InvalidHeader!DB {
return result; return result;
} }
pub fn packCGroupNoMembers(group: PackedGroup, buf: []u8) error{BufferTooSmall}!CGroup {
// first word in buf will be a pointer to null. that probably can be
// simplified by writing (0)**word_size to the buffer, but let's pretend
// type safety for a moment.
const name_start = @sizeOf(?[*:0]const u8);
if (name_start > buf.len) return error.BufferTooSmall;
var member_ptrs = mem.bytesAsSlice(?[*:0]const u8, buf[0..name_start]);
member_ptrs[0] = null;
// write name
const name = group.name();
if (name_start + name.len + 1 > buf.len) return error.BufferTooSmall;
mem.copy(u8, buf[name_start..], name);
buf[name_start + name.len] = 0;
return CGroup{
.gid = group.gid(),
.name = buf[name_start .. name_start + name.len :0].ptr,
.members = member_ptrs.ptr,
};
}
// dumps PackedGroup to []u8 and returns a CGroup. // dumps PackedGroup to []u8 and returns a CGroup.
pub fn packCGroup(self: *const DB, group: PackedGroup, buf: []u8) error{BufferTooSmall}!CGroup { pub fn packCGroup(self: *const DB, group: PackedGroup, buf: []u8) error{BufferTooSmall}!CGroup {
const members_slice = self.groupmembers[group.members_offset..]; const members_slice = self.groupmembers[group.members_offset..];
@ -321,25 +343,41 @@ pub fn packCGroup(self: *const DB, group: PackedGroup, buf: []u8) error{BufferTo
} }
// get a CGroup entry by name. // get a CGroup entry by name.
pub fn getgrnam(self: *const DB, name: []const u8, buf: []u8) error{BufferTooSmall}!?CGroup { pub fn getgrnam(
self: *const DB,
name: []const u8,
buf: []u8,
omit_members: bool,
) error{BufferTooSmall}!?CGroup {
const idx = bdz.search(self.bdz_groupname, name); const idx = bdz.search(self.bdz_groupname, name);
if (idx >= self.header.num_groups) return null; if (idx >= self.header.num_groups) return null;
const offset = self.idx_groupname2group[idx]; const offset = self.idx_groupname2group[idx];
const nbits = PackedGroup.alignment_bits; const nbits = PackedGroup.alignment_bits;
const group = PackedGroup.fromBytes(self.groups[offset << nbits ..]).group; const group = PackedGroup.fromBytes(self.groups[offset << nbits ..]).group;
if (!mem.eql(u8, name, group.name())) return null; if (!mem.eql(u8, name, group.name())) return null;
return try self.packCGroup(group, buf); return if (omit_members)
try packCGroupNoMembers(group, buf)
else
try self.packCGroup(group, buf);
} }
// get a CGroup entry by it's gid. // get a CGroup entry by it's gid.
pub fn getgrgid(self: *const DB, gid: u32, buf: []u8) error{BufferTooSmall}!?CGroup { pub fn getgrgid(
self: *const DB,
gid: u32,
buf: []u8,
omit_members: bool,
) error{BufferTooSmall}!?CGroup {
const idx = bdz.search_u32(self.bdz_gid, gid); const idx = bdz.search_u32(self.bdz_gid, gid);
if (idx >= self.header.num_groups) return null; if (idx >= self.header.num_groups) return null;
const offset = self.idx_gid2group[idx]; const offset = self.idx_gid2group[idx];
const nbits = PackedGroup.alignment_bits; const nbits = PackedGroup.alignment_bits;
const group = PackedGroup.fromBytes(self.groups[offset << nbits ..]).group; const group = PackedGroup.fromBytes(self.groups[offset << nbits ..]).group;
if (gid != group.gid()) return null; if (gid != group.gid()) return null;
return try self.packCGroup(group, buf); return if (omit_members)
try packCGroupNoMembers(group, buf)
else
try self.packCGroup(group, buf);
} }
fn pushStr(str: []const u8, buf: []u8, offset: *usize) [*:0]const u8 { fn pushStr(str: []const u8, buf: []u8, offset: *usize) [*:0]const u8 {
@ -708,8 +746,8 @@ test "getgrnam/getgrgid" {
defer testing.allocator.free(buf); defer testing.allocator.free(buf);
{ {
try testing.expectEqual(try db.getgrnam("doesnotexist", buf), null); try testing.expectEqual(try db.getgrnam("doesnotexist", buf, false), null);
const all = (try db.getgrnam("all", buf)).?; const all = (try db.getgrnam("all", buf, false)).?;
try testing.expectEqual(all.gid, 9999); try testing.expectEqual(all.gid, 9999);
try testing.expectEqualStrings(all.name[0..4], "all\x00"); try testing.expectEqualStrings(all.name[0..4], "all\x00");
const members = all.members; const members = all.members;
@ -721,16 +759,23 @@ test "getgrnam/getgrgid" {
} }
{ {
try testing.expectEqual(try db.getgrgid(42, buf), null); const all = (try db.getgrnam("all", buf, true)).?;
const all = (try db.getgrgid(9999, buf)).?; try testing.expectEqual(all.gid, 9999);
try testing.expectEqualStrings(all.name[0..4], "all\x00");
try testing.expectEqual(all.members[0], null);
}
{
try testing.expectEqual(try db.getgrgid(42, buf, false), null);
const all = (try db.getgrgid(9999, buf, false)).?;
try testing.expectEqual(all.gid, 9999); try testing.expectEqual(all.gid, 9999);
try testing.expectEqualStrings(all.name[0..3], "all"); try testing.expectEqualStrings(all.name[0..3], "all");
} }
try testing.expectEqualStrings("", errc.unwrap().constSlice()); try testing.expectEqualStrings("", errc.unwrap().constSlice());
_ = try db.getgrnam("all", buf); _ = try db.getgrnam("all", buf, false);
buf.len -= 1; buf.len -= 1;
try testing.expectError(error.BufferTooSmall, db.getgrnam("all", buf)); try testing.expectError(error.BufferTooSmall, db.getgrnam("all", buf, false));
} }
test "getpwnam/getpwuid" { test "getpwnam/getpwuid" {

View File

@ -160,8 +160,12 @@ export fn _nss_turbo_getgrgid_r(
buflen: usize, buflen: usize,
errnop: *c_int, errnop: *c_int,
) c.enum_nss_status { ) c.enum_nss_status {
const db = getDBErrno(errnop) orelse return c.NSS_STATUS_UNAVAIL; const state = getStateErrno(errnop) orelse return c.NSS_STATUS_UNAVAIL;
var cgroup = db.getgrgid(gid, buffer[0..buflen]) catch |err| switch (err) { const db = state.file.db;
const omit_members = state.omit_members;
var buf = buffer[0..buflen];
var cgroup = db.getgrgid(gid, buf, omit_members) catch |err| switch (err) {
error.BufferTooSmall => { error.BufferTooSmall => {
errnop.* = @enumToInt(os.E.RANGE); errnop.* = @enumToInt(os.E.RANGE);
return c.NSS_STATUS_TRYAGAIN; return c.NSS_STATUS_TRYAGAIN;
@ -184,10 +188,13 @@ export fn _nss_turbo_getgrnam_r(
buflen: usize, buflen: usize,
errnop: *c_int, errnop: *c_int,
) c.enum_nss_status { ) c.enum_nss_status {
const db = getDBErrno(errnop) orelse return c.NSS_STATUS_UNAVAIL; const state = getStateErrno(errnop) orelse return c.NSS_STATUS_UNAVAIL;
const db = state.file.db;
const omit_members = state.omit_members;
const nameSlice = mem.sliceTo(name, 0); const nameSlice = mem.sliceTo(name, 0);
var buf = buffer[0..buflen]; var buf = buffer[0..buflen];
var cgroup = db.getgrnam(nameSlice, buf) catch |err| switch (err) { var cgroup = db.getgrnam(nameSlice, buf, omit_members) catch |err| switch (err) {
error.BufferTooSmall => { error.BufferTooSmall => {
errnop.* = @enumToInt(os.E.RANGE); errnop.* = @enumToInt(os.E.RANGE);
return c.NSS_STATUS_TRYAGAIN; return c.NSS_STATUS_TRYAGAIN;
@ -267,16 +274,20 @@ export fn _nss_turbo_getgrent_r(
return c.NSS_STATUS_NOTFOUND; return c.NSS_STATUS_NOTFOUND;
}; };
const buf = buffer[0..buflen]; const cgroup1 = if (state.omit_members)
const cgroup = state.file.db.packCGroup(group, buf) catch |err| switch (err) { DB.packCGroupNoMembers(group, buffer[0..buflen])
else
state.file.db.packCGroup(group, buffer[0..buflen]);
if (cgroup1) |cgroup| {
result.* = cgroup;
return c.NSS_STATUS_SUCCESS;
} else |err| switch (err) {
error.BufferTooSmall => { error.BufferTooSmall => {
errnop.* = @enumToInt(os.E.RANGE); errnop.* = @enumToInt(os.E.RANGE);
return c.NSS_STATUS_TRYAGAIN; return c.NSS_STATUS_TRYAGAIN;
}, },
}; }
result.* = cgroup;
return c.NSS_STATUS_SUCCESS;
} }
export fn _nss_turbo_getpwent_r( export fn _nss_turbo_getpwent_r(