79 lines
2.6 KiB
Zig
79 lines
2.6 KiB
Zig
const builtin = @import("builtin");
|
|
const Os = builtin.Os;
|
|
const os = @import("index.zig");
|
|
const io = @import("../io.zig");
|
|
|
|
/// POSIX function which gets a uid from username.
|
|
pub fn getUserId(name: []const u8) -> %u32 {
|
|
return switch (builtin.os) {
|
|
Os.linux, Os.darwin, Os.macosx, Os.ios => posixGetUserId(name),
|
|
else => @compileError("Unsupported OS"),
|
|
};
|
|
}
|
|
|
|
const State = enum {
|
|
Start,
|
|
WaitForNextLine,
|
|
SkipPassword,
|
|
ReadId,
|
|
};
|
|
|
|
error UserNotFound;
|
|
error CorruptPasswordFile;
|
|
|
|
pub fn posixGetUserId(name: []const u8) -> %u32 {
|
|
var in_stream = %return io.InStream.open("/etc/passwd", null);
|
|
defer in_stream.close();
|
|
|
|
var buf: [os.page_size]u8 = undefined;
|
|
var name_index: usize = 0;
|
|
var state = State.Start;
|
|
var uid: u32 = 0;
|
|
|
|
while (true) {
|
|
const amt_read = %return in_stream.read(buf[0..]);
|
|
for (buf[0..amt_read]) |byte| {
|
|
switch (state) {
|
|
State.Start => switch (byte) {
|
|
':' => {
|
|
state = if (name_index == name.len) State.SkipPassword else State.WaitForNextLine;
|
|
},
|
|
'\n' => return error.CorruptPasswordFile,
|
|
else => {
|
|
if (name_index == name.len or name[name_index] != byte) {
|
|
state = State.WaitForNextLine;
|
|
}
|
|
name_index += 1;
|
|
},
|
|
},
|
|
State.WaitForNextLine => switch (byte) {
|
|
'\n' => {
|
|
name_index = 0;
|
|
state = State.Start;
|
|
},
|
|
else => continue,
|
|
},
|
|
State.SkipPassword => switch (byte) {
|
|
'\n' => return error.CorruptPasswordFile,
|
|
':' => {
|
|
state = State.ReadId;
|
|
},
|
|
else => continue,
|
|
},
|
|
State.ReadId => switch (byte) {
|
|
'\n', ':' => return uid,
|
|
else => {
|
|
const digit = switch (byte) {
|
|
'0' ... '9' => byte - '0',
|
|
else => return error.CorruptPasswordFile,
|
|
};
|
|
if (@mulWithOverflow(u32, uid, 10, &uid)) return error.CorruptPasswordFile;
|
|
if (@addWithOverflow(u32, uid, digit, &uid)) return error.CorruptPasswordFile;
|
|
},
|
|
},
|
|
}
|
|
}
|
|
if (amt_read < buf.len) return error.UserNotFound;
|
|
}
|
|
}
|