From eaccd009607fd447e4e8123cf55fbc65a9c7ad7c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Motiejus=20Jak=C5=A1tys?= Date: Mon, 4 Jul 2022 06:09:03 +0300 Subject: [PATCH] handle duplicate gid --- src/Corpus.zig | 48 ++++++++++++++++++++++++++++++++++++------------ src/DB.zig | 16 +++++++++++++--- src/File.zig | 5 +++-- src/libnss.zig | 4 +++- src/unix2db.zig | 4 ++-- 5 files changed, 57 insertions(+), 20 deletions(-) diff --git a/src/Corpus.zig b/src/Corpus.zig index c15b374..be0eba6 100644 --- a/src/Corpus.zig +++ b/src/Corpus.zig @@ -5,6 +5,7 @@ const sort = std.sort; const unicode = std.unicode; const Allocator = std.mem.Allocator; const ArenaAllocator = std.heap.ArenaAllocator; +const AutoHashMap = std.AutoHashMap; const StringHashMap = std.StringHashMap; const MultiArrayList = std.MultiArrayList; const ArrayListUnmanaged = std.ArrayListUnmanaged; @@ -69,20 +70,43 @@ pub fn init( for (groups_arr) |group| groups.appendAssumeCapacity(group); + // verify whatever comes to cmph are unique: user names var name2user = StringHashMap(u32).init(allocator); - var name2group = StringHashMap(u32).init(allocator); for (users.items(.name)) |name, i| { - var res1 = try name2user.getOrPut(name); - if (res1.found_existing) + var result = try name2user.getOrPut(name); + if (result.found_existing) return error.Duplicate; - res1.value_ptr.* = @intCast(u32, i); + result.value_ptr.* = @intCast(u32, i); + } + // verify whatever comes to cmph are unique: group names + var name2group = StringHashMap(u32).init(allocator); + for (groups.items(.name)) |name, i| { + var result = try name2group.getOrPut(name); + if (result.found_existing) + return error.Duplicate; + result.value_ptr.* = @intCast(u32, i); } - for (groups.items(.name)) |name, i| { - var res1 = try name2group.getOrPut(name); - if (res1.found_existing) - return error.Duplicate; - res1.value_ptr.* = @intCast(u32, i); + // verify whatever comes to cmph are unique: gids + { + const gids = groups.items(.gid); + var last_gid = gids[0]; + for (gids[1..]) |gid| { + if (gid == last_gid) + return err.returnf("duplicate gid {d}", .{gid}, error.Duplicate); + last_gid = gid; + } + } + + // verify whatever comes to cmph are unique: uids + { + var uid_map = AutoHashMap(u32, void).init(allocator); + defer uid_map.deinit(); + for (users.items(.uid)) |uid| { + const result = try uid_map.getOrPut(uid); + if (result.found_existing) + return err.returnf("duplicate uid {d}", .{uid}, error.Duplicate); + } } var group2users = try allocator.alloc([]u32, groups.len); @@ -236,9 +260,9 @@ pub fn testCorpus(allocator: Allocator) !Corpus { const groups = [_]Group{ group0, group1, group2, group3 }; - var err_ctx = ErrCtx{}; - const result = try Corpus.init(allocator, users[0..], groups[0..], &err_ctx); - try testing.expectEqualStrings("", err_ctx.unwrap().constSlice()); + var errc = ErrCtx{}; + const result = try Corpus.init(allocator, users[0..], groups[0..], &errc); + try testing.expectEqualStrings("", errc.unwrap().constSlice()); return result; } diff --git a/src/DB.zig b/src/DB.zig index 0b88714..1c6accc 100644 --- a/src/DB.zig +++ b/src/DB.zig @@ -10,6 +10,7 @@ const ArrayList = std.ArrayList; const AutoHashMap = std.AutoHashMap; const BoundedArray = std.BoundedArray; +const ErrCtx = @import("ErrCtx.zig"); const Corpus = @import("Corpus.zig"); const pad = @import("padding.zig"); const compress = @import("compress.zig"); @@ -54,7 +55,10 @@ additional_gids: []const u8, pub fn fromCorpus( allocator: Allocator, corpus: *const Corpus, + err: *ErrCtx, ) error{ OutOfMemory, InvalidRecord, TooMany }!DB { + _ = err; + const gids = corpus.groups.items(.gid); const gnames = corpus.groups.items(.name); const uids = corpus.users.items(.uid); @@ -630,7 +634,8 @@ test "read/write via iovec" { var corpus = try Corpus.testCorpus(allocator); defer corpus.deinit(); - var db = try DB.fromCorpus(allocator, &corpus); + var errc = ErrCtx{}; + var db = try DB.fromCorpus(allocator, &corpus, &errc); defer db.deinit(allocator); const fd = try os.memfd_create("test_turbonss_db", 0); @@ -648,12 +653,14 @@ test "read/write via iovec" { try testing.expectEqualSlices(u32, db.idx_gid2group, db2.idx_gid2group[0..num_groups]); try testing.expectEqualSlices(u32, db.idx_uid2user, db2.idx_uid2user[0..num_users]); + try testing.expectEqualStrings("", errc.unwrap().constSlice()); } test "getgrnam/getgrgid" { var corpus = try Corpus.testCorpus(testing.allocator); defer corpus.deinit(); - var db = try DB.fromCorpus(testing.allocator, &corpus); + var errc = ErrCtx{}; + var db = try DB.fromCorpus(testing.allocator, &corpus, &errc); defer db.deinit(testing.allocator); var buf = try testing.allocator.alloc(u8, db.getgrBufsize()); defer testing.allocator.free(buf); @@ -677,6 +684,7 @@ test "getgrnam/getgrgid" { try testing.expectEqual(all.gid, 9999); try testing.expectEqualStrings(all.name[0..3], "all"); } + try testing.expectEqualStrings("", errc.unwrap().constSlice()); _ = try db.getgrnam("all", buf); buf.len -= 1; @@ -686,7 +694,8 @@ test "getgrnam/getgrgid" { test "getpwnam/getpwuid" { var corpus = try Corpus.testCorpus(testing.allocator); defer corpus.deinit(); - var db = try DB.fromCorpus(testing.allocator, &corpus); + var errc = ErrCtx{}; + var db = try DB.fromCorpus(testing.allocator, &corpus, &errc); defer db.deinit(testing.allocator); var buf = try testing.allocator.alloc(u8, db.getpwBufsize()); defer testing.allocator.free(buf); @@ -708,6 +717,7 @@ test "getpwnam/getpwuid" { try testing.expectEqual(vidmantas.pw_gid, 128); try testing.expectEqualStrings(vidmantas.pw_name[0..10], "vidmantas\x00"); } + try testing.expectEqualStrings("", errc.unwrap().constSlice()); const long = try db.getpwnam("Name" ** 8, buf); try testing.expectEqualStrings(long.?.pw_name[0..33], "Name" ** 8 ++ "\x00"); diff --git a/src/File.zig b/src/File.zig index 46944b4..69bae7b 100644 --- a/src/File.zig +++ b/src/File.zig @@ -5,6 +5,7 @@ const Allocator = std.mem.Allocator; const Corpus = @import("Corpus.zig"); const DB = @import("DB.zig"); +const ErrCtx = @import("ErrCtx.zig"); const InvalidHeader = @import("header.zig").Invalid; const File = @This(); @@ -42,11 +43,11 @@ pub const TestDB = struct { dir: testing.TmpDir, path: [:0]const u8, - pub fn init(allocator: Allocator) !TestDB { + pub fn init(allocator: Allocator, errc: *ErrCtx) !TestDB { var corpus = try Corpus.testCorpus(allocator); defer corpus.deinit(); - var db = try DB.fromCorpus(allocator, &corpus); + var db = try DB.fromCorpus(allocator, &corpus, errc); defer db.deinit(allocator); var tmp = testing.tmpDir(.{}); diff --git a/src/libnss.zig b/src/libnss.zig index 87649a6..6975527 100644 --- a/src/libnss.zig +++ b/src/libnss.zig @@ -6,6 +6,7 @@ const process = std.process; const DB = @import("DB.zig"); const File = @import("File.zig"); +const ErrCtx = @import("ErrCtx.zig"); const CGroup = @import("Group.zig").CGroup; const PackedGroup = @import("PackedGroup.zig"); const CUser = @import("User.zig").CUser; @@ -131,7 +132,8 @@ export fn _nss_turbo_getpwuid_r( const testing = std.testing; test "nss_turbo_getpwuid_r" { - var tf = try File.TestDB.init(testing.allocator); + var errc = ErrCtx{}; + var tf = try File.TestDB.init(testing.allocator, &errc); defer tf.deinit(); var env = try process.getEnvMap(testing.allocator); diff --git a/src/unix2db.zig b/src/unix2db.zig index 28dbdd2..af3d55b 100644 --- a/src/unix2db.zig +++ b/src/unix2db.zig @@ -97,8 +97,8 @@ fn execute( return fail(errc.wrap("init corpus"), stderr, err); defer corpus.deinit(); - var db = DB.fromCorpus(allocator, &corpus) catch |err| - return fail(errc.wrap("construct db from corpus"), stderr, err); + var db = DB.fromCorpus(allocator, &corpus, &errc) catch |err| + return fail(errc.wrap("construct DB from corpus"), stderr, err); defer db.deinit(allocator); const fd = os.open(outFile, os.O.WRONLY | os.O.TRUNC | os.O.CREAT, 0644) catch |err|