1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-27 17:27:35 +00:00

LibC+Tests: Simplify getpwuid_r() and getpwnam_r() and add tests

These functions are now implemented in terms of getpwent_r() which
allows us to remove two FIXMEs about global variable shenanigans.

I'm also adding tests for both APIs. :^)
This commit is contained in:
Andreas Kling 2022-11-17 20:43:42 +01:00
parent cc189ce0f3
commit 524baa29e8
3 changed files with 135 additions and 85 deletions

View file

@ -20,12 +20,6 @@ extern "C" {
static FILE* s_stream = nullptr;
static unsigned s_line_number = 0;
static String s_name;
static String s_passwd;
static String s_gecos;
static String s_dir;
static String s_shell;
void setpwent()
{
s_line_number = 0;
@ -163,91 +157,28 @@ int getpwent_r(struct passwd* passwd_buf, char* buffer, size_t buffer_size, stru
}
}
static void construct_pwd(struct passwd* pwd, char* buf, struct passwd** result)
// https://pubs.opengroup.org/onlinepubs/9699919799/functions/getpwnam.html
int getpwnam_r(char const* name, struct passwd* pwd, char* buffer, size_t bufsize, struct passwd** result)
{
auto* buf_name = &buf[0];
auto* buf_passwd = &buf[s_name.length() + 1];
auto* buf_gecos = &buf[s_name.length() + 1 + s_gecos.length() + 1];
auto* buf_dir = &buf[s_gecos.length() + 1 + s_name.length() + 1 + s_gecos.length() + 1];
auto* buf_shell = &buf[s_dir.length() + 1 + s_gecos.length() + 1 + s_name.length() + 1 + s_gecos.length() + 1];
bool ok = true;
ok = ok && s_name.copy_characters_to_buffer(buf_name, s_name.length() + 1);
ok = ok && s_passwd.copy_characters_to_buffer(buf_passwd, s_passwd.length() + 1);
ok = ok && s_gecos.copy_characters_to_buffer(buf_gecos, s_gecos.length() + 1);
ok = ok && s_dir.copy_characters_to_buffer(buf_dir, s_dir.length() + 1);
ok = ok && s_shell.copy_characters_to_buffer(buf_shell, s_shell.length() + 1);
VERIFY(ok);
*result = pwd;
pwd->pw_name = buf_name;
pwd->pw_passwd = buf_passwd;
pwd->pw_gecos = buf_gecos;
pwd->pw_dir = buf_dir;
pwd->pw_shell = buf_shell;
setpwent();
for (;;) {
if (auto rc = getpwent_r(pwd, buffer, bufsize, result); rc != 0)
return rc;
if (strcmp(pwd->pw_name, name) == 0)
return 0;
}
}
int getpwnam_r(char const* name, struct passwd* pwd, char* buf, size_t buflen, struct passwd** result)
// https://pubs.opengroup.org/onlinepubs/9699919799/functions/getpwuid.html
int getpwuid_r(uid_t uid, struct passwd* pwd, char* buffer, size_t bufsize, struct passwd** result)
{
// FIXME: This is a HACK!
TemporaryChange name_change { s_name, {} };
TemporaryChange passwd_change { s_passwd, {} };
TemporaryChange gecos_change { s_gecos, {} };
TemporaryChange dir_change { s_dir, {} };
TemporaryChange shell_change { s_shell, {} };
setpwent();
bool found = false;
while (auto* pw = getpwent()) {
if (!strcmp(pw->pw_name, name)) {
found = true;
break;
}
for (;;) {
if (auto rc = getpwent_r(pwd, buffer, bufsize, result); rc != 0)
return rc;
if (pwd->pw_uid == uid)
return 0;
}
if (!found) {
*result = nullptr;
return 0;
}
auto const total_buffer_length = s_name.length() + s_passwd.length() + s_gecos.length() + s_dir.length() + s_shell.length() + 5;
if (buflen < total_buffer_length)
return ERANGE;
construct_pwd(pwd, buf, result);
return 0;
}
int getpwuid_r(uid_t uid, struct passwd* pwd, char* buf, size_t buflen, struct passwd** result)
{
// FIXME: This is a HACK!
TemporaryChange name_change { s_name, {} };
TemporaryChange passwd_change { s_passwd, {} };
TemporaryChange gecos_change { s_gecos, {} };
TemporaryChange dir_change { s_dir, {} };
TemporaryChange shell_change { s_shell, {} };
setpwent();
bool found = false;
while (auto* pw = getpwent()) {
if (pw->pw_uid == uid) {
found = true;
break;
}
}
if (!found) {
*result = nullptr;
return 0;
}
auto const total_buffer_length = s_name.length() + s_passwd.length() + s_gecos.length() + s_dir.length() + s_shell.length() + 5;
if (buflen < total_buffer_length)
return ERANGE;
construct_pwd(pwd, buf, result);
return 0;
}
int putpwent(const struct passwd* p, FILE* stream)