romele / git-trace public
62 commits · 1 branch · 1 tag · 1 contributor (top: Romele) · first commit 3d ago · last push 10m ago
src/gitx.c
#include "gitx.h" #include <ctype.h> #include <fcntl.h> #include <signal.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/wait.h> #include <unistd.h> #define CAP_MAX (16 * 1024 * 1024) int git_ref_ok(const char *s) { size_t n = strlen(s); if (n == 0 || n > 255) return 0; if (s[0] == '-' || s[0] == '/' || s[0] == '.') return 0; if (strstr(s, "..")) return 0; for (size_t i = 0; i < n; i++) { unsigned char c = (unsigned char)s[i]; if (!(isalnum(c) || c == '.' || c == '_' || c == '-' || c == '/')) return 0; } return 1; } int git_path_ok(const char *s) { size_t n = strlen(s); if (n == 0) return 1; /* empty = tree root */ if (n > 1024 || s[0] == '-' || s[0] == '/') return 0; if (strstr(s, "..")) return 0; for (size_t i = 0; i < n; i++) { unsigned char c = (unsigned char)s[i]; if (!(isalnum(c) || c == '.' || c == '_' || c == '-' || c == '/' || c == ' ' || c == '+' || c == '(' || c == ')' || c == '@')) return 0; } return 1; } int git_pat_ok(const char *s) { size_t n = strlen(s); if (n == 0 || n > 255) return 0; if (s[0] == '-' || s[0] == '/' || s[0] == '.') return 0; if (strstr(s, "..")) return 0; for (size_t i = 0; i < n; i++) { unsigned char c = (unsigned char)s[i]; if (!(isalnum(c) || c == '.' || c == '_' || c == '-' || c == '/' || c == '*' || c == '?')) return 0; } return 1; } static int capture_impl(const char *repo_dir, const char *const envs[], const char *const argv[], struct buf *out) { int pfd[2]; if (pipe(pfd) < 0) return -1; pid_t pid = fork(); if (pid < 0) { close(pfd[0]); close(pfd[1]); return -1; } if (pid == 0) { dup2(pfd[1], 1); close(pfd[0]); close(pfd[1]); int devnull = open("/dev/null", 1); if (devnull >= 0) dup2(devnull, 2); if (chdir(repo_dir) != 0) _exit(127); if (envs) for (int i = 0; envs[i]; i++) putenv((char *)envs[i]); execvp("git", (char *const *)argv); _exit(127); } close(pfd[1]); int overflow = 0; char tmp[16384]; for (;;) { ssize_t n = read(pfd[0], tmp, sizeof tmp); if (n <= 0) break; if (out->len + (size_t)n > CAP_MAX) { overflow = 1; kill(pid, SIGKILL); break; } buf_put(out, tmp, (size_t)n); } close(pfd[0]); int st = 0; waitpid(pid, &st, 0); if (overflow) return -2; return WIFEXITED(st) ? WEXITSTATUS(st) : -1; } int git_capture(const char *repo_dir, const char *const argv[], struct buf *out) { return capture_impl(repo_dir, NULL, argv, out); } int git_capture_env(const char *repo_dir, const char *const envs[], const char *const argv[], struct buf *out) { return capture_impl(repo_dir, envs, argv, out); } char *git_default_branch(const char *repo_dir) { struct buf b; buf_init(&b); const char *argv[] = { "git", "symbolic-ref", "--short", "-q", "HEAD", NULL }; if (git_capture(repo_dir, argv, &b) != 0 || b.len == 0) { buf_free(&b); return NULL; } char *nl = strchr(b.data, '\n'); if (nl) *nl = '\0'; return b.data; }