Group.fromReader
This commit is contained in:
parent
e238db9b60
commit
31b5bb2d72
@ -1,8 +1,11 @@
|
||||
const std = @import("std");
|
||||
|
||||
const os = std.os;
|
||||
const mem = std.mem;
|
||||
const fmt = std.fmt;
|
||||
const meta = std.meta;
|
||||
const maxInt = std.math.maxInt;
|
||||
const Allocator = mem.Allocator;
|
||||
const ArrayList = std.ArrayList;
|
||||
const Group = @This();
|
||||
|
||||
gid: u32,
|
||||
@ -55,6 +58,45 @@ pub fn deinit(self: *Group, allocator: Allocator) void {
|
||||
self.* = undefined;
|
||||
}
|
||||
|
||||
pub const FromReaderError = error{ InvalidRecord, OutOfMemory } || os.ReadError;
|
||||
|
||||
pub fn fromReader(allocator: Allocator, reader: anytype) FromReaderError![]Group {
|
||||
var groups = ArrayList(Group).init(allocator);
|
||||
var member_ptrs = ArrayList([]const u8).init(allocator);
|
||||
defer member_ptrs.deinit();
|
||||
var line = ArrayList(u8).init(allocator);
|
||||
defer line.deinit();
|
||||
|
||||
while (true) {
|
||||
// TODO: catch and interpret different errors
|
||||
const max = std.math.maxInt(u32);
|
||||
reader.readUntilDelimiterArrayList(&line, '\n', max) catch |err| switch (err) {
|
||||
error.EndOfStream => break,
|
||||
error.StreamTooLong => unreachable,
|
||||
else => |e| return e,
|
||||
};
|
||||
|
||||
var it = mem.split(u8, line.items, ":");
|
||||
const name = it.next() orelse return error.InvalidRecord;
|
||||
_ = it.next() orelse return error.InvalidRecord; // password
|
||||
const gids = it.next() orelse return error.InvalidRecord;
|
||||
const members_commas = it.next() orelse return error.InvalidRecord;
|
||||
// the line must be exhaustive.
|
||||
if (it.next() != null) return error.InvalidRecord;
|
||||
|
||||
const gid = fmt.parseInt(u32, gids, 10) catch return error.InvalidRecord;
|
||||
|
||||
var members_it = mem.split(u8, members_commas, ",");
|
||||
while (members_it.next()) |member|
|
||||
try member_ptrs.append(member);
|
||||
|
||||
try groups.append(try init(allocator, gid, name, member_ptrs.items));
|
||||
member_ptrs.shrinkRetainingCapacity(0);
|
||||
}
|
||||
|
||||
return groups.toOwnedSlice();
|
||||
}
|
||||
|
||||
// suggested buffer size in bytes if all strings were zero-terminated
|
||||
// (for CGroup).
|
||||
pub fn strlenZ(self: *const Group) usize {
|
||||
|
@ -43,15 +43,14 @@ pub fn clone(
|
||||
};
|
||||
}
|
||||
|
||||
const line_fmt = "{s}:x:{d}:{d}:{s}:{s}:{s}\n";
|
||||
|
||||
// fromLine accepts a line of /etc/passwd (with or without the EOL) and makes a
|
||||
// User.
|
||||
fn fromLine(allocator: Allocator, line: []const u8) error{ InvalidRecord, OutOfMemory }!User {
|
||||
var it = mem.split(u8, line, ":");
|
||||
const name = it.next() orelse return error.InvalidRecord;
|
||||
_ = it.next() orelse return error.InvalidRecord; // password
|
||||
const uids = it.next() orelse return error.InvalidRecord;
|
||||
const gids = it.next() orelse return error.InvalidRecord;
|
||||
const name = it.next() orelse return error.InvalidRecord;
|
||||
const gecos = it.next() orelse return error.InvalidRecord;
|
||||
const home = it.next() orelse return error.InvalidRecord;
|
||||
const shell = it.next() orelse return error.InvalidRecord;
|
||||
@ -84,6 +83,8 @@ fn strlen(self: *const User) usize {
|
||||
self.shell.len;
|
||||
}
|
||||
|
||||
const line_fmt = "{s}:x:{d}:{d}:{s}:{s}:{s}\n";
|
||||
|
||||
const max_line_len = fmt.count(line_fmt, .{
|
||||
max_user.name,
|
||||
max_user.uid,
|
||||
@ -120,7 +121,7 @@ pub fn deinit(self: *User, allocator: Allocator) void {
|
||||
|
||||
pub fn fromReader(allocator: Allocator, reader: anytype) ![]User {
|
||||
var users = ArrayList(User).init(allocator);
|
||||
var buf: [max_line_len]u8 = undefined;
|
||||
var buf: [max_line_len + 1]u8 = undefined;
|
||||
// TODO: catch and interpret error
|
||||
while (try reader.readUntilDelimiterOrEof(buf[0..], '\n')) |line| {
|
||||
const user = try fromLine(allocator, line);
|
||||
|
@ -9,6 +9,7 @@ const GeneralPurposeAllocator = std.heap.GeneralPurposeAllocator;
|
||||
|
||||
const flags = @import("../flags.zig");
|
||||
const User = @import("../User.zig");
|
||||
const Group = @import("../Group.zig");
|
||||
|
||||
const usage =
|
||||
\\usage: turbonss-unix2db [options]
|
||||
@ -66,8 +67,10 @@ fn execute(
|
||||
defer groupFile.close();
|
||||
|
||||
var users = try User.fromReader(allocator, passwdFile.reader());
|
||||
var groups = try Group.fromReader(allocator, groupFile.reader());
|
||||
|
||||
try stderr.print("read {d} users\n", .{users.len});
|
||||
try stderr.print("read {d} groups\n", .{groups.len});
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user