[libc-commits] [libc] [libc] Add struct group header and group line parser (PR #224208)
Michael Jones via libc-commits
libc-commits at lists.llvm.org
Thu Sep 17 08:51:59 PDT 2026
================
@@ -0,0 +1,199 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// Implementation of helper functions and parser for grp.
+///
+//===----------------------------------------------------------------------===//
+
+#include "src/grp/grp_utils.h"
+#include "hdr/errno_macros.h"
+#include "hdr/stdint_proxy.h"
+#include "hdr/types/gid_t.h"
+#include "hdr/types/size_t.h"
+#include "hdr/types/struct_group.h"
+#include "src/__support/CPP/span.h"
+#include "src/__support/ctype_utils.h"
+#include "src/__support/error_or.h"
+#include "src/__support/macros/attributes.h"
+#include "src/__support/macros/config.h"
+#include "src/__support/pwd/dynamic_buffer.h"
+#include "src/__support/pwd/field_tokenizer.h"
+#include "src/__support/pwd/flat_file_db.h"
+#include "src/__support/str_to_integer.h"
+
+#ifndef LIBC_COPT_GROUP_FILE_PATH
+#define LIBC_COPT_GROUP_FILE_PATH "/etc/group"
+#endif
+
+namespace LIBC_NAMESPACE_DECL {
+namespace {
+
+// TODO: Replace with cpp::count when available in
+// src/__support/CPP/algorithm.h.
+size_t count_group_members(cpp::span<const char> line) {
+ size_t max_members = 1;
+ for (char c : line) {
+ if (c == ',')
+ ++max_members;
+ }
+ return max_members;
+}
+
+// Parse fixed fields (name, passwd, gid).
+bool parse_group_fields(cpp::span<char> line, struct group *grp,
+ cpp::span<char> *members_out) {
+ if (line.empty() || !grp || !members_out)
+ return false;
+
+ pwd::FieldTokenizer tokenizer(line, ':');
+
+ auto name = tokenizer.next_field();
+ if (!name || name->empty() || name->front() == '\0')
+ return false;
+ grp->gr_name = name->data();
+
+ auto passwd = tokenizer.next_field();
+ if (!passwd)
+ return false;
+ grp->gr_passwd = passwd->data();
+
+ auto gid_str = tokenizer.next_field();
+ if (!gid_str || gid_str->empty() || !internal::isdigit(gid_str->front()))
+ return false;
+ auto gid_res = internal::strtointeger<gid_t>(gid_str->data(), 10);
+ if (gid_res.has_error() || gid_res.parsed_len <= 0 ||
+ static_cast<size_t>(gid_res.parsed_len) + 1 != gid_str->size() ||
+ (*gid_str)[gid_res.parsed_len] != '\0')
+ return false;
+ grp->gr_gid = gid_res.value;
+
+ auto members_field = tokenizer.next_field();
+ if (!members_field)
+ return false;
+
+ // Trailing delimiters or fields are invalid.
+ if (tokenizer.next_field())
+ return false;
+
+ *members_out = *members_field;
+ return true;
+}
+
+} // namespace
+
+namespace pwd {
+
+template <>
+ErrorOr<void> parse_line<struct group>(cpp::span<char> line,
+ cpp::span<char> scratch,
+ struct group *grp) {
+ if (!grp || line.empty() || line.back() != '\0')
+ return Error(EINVAL);
+
+ // Line excluding terminating null byte.
+ cpp::span<char> text = line.first(line.size() - 1);
+ for (char c : text) {
+ if (c == '\0')
+ return Error(EINVAL);
+ }
+
+ size_t max_members = count_group_members(text);
+ uintptr_t tail = reinterpret_cast<uintptr_t>(scratch.data());
+ size_t pad = (alignof(char *) - tail % alignof(char *)) % alignof(char *);
----------------
michaelrj-google wrote:
maybe add a comment explaining what you're calculating here? It's a bit hard to parse. Also `pad` is never modified and could be const. Same for some of the other variables.
https://github.com/llvm/llvm-project/pull/224208
More information about the libc-commits
mailing list