git-off

git off handles large files in git repos
git clone https://noulin.net/git/git-off.git
Log | Files | Refs | README

commit 1782bae59246ceaedd262b6502e47cacc5894db9
parent 72dfecd782b5a99ace6bee35077ce710c07f023e
Author: rlp <rlp@openbsd.localdomain>
Date:   Sun,  9 Dec 2018 09:56:43 +0100

add support for OpenBSD

Diffstat:
Mc/gitoff.c | 312+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 312 insertions(+), 0 deletions(-)

diff --git a/c/gitoff.c b/c/gitoff.c @@ -85,7 +85,9 @@ typedef void (*cmdSetF_t)(gConfig_set_t); #include <stdio.h> #include <dirent.h> #include <libgen.h> +#if (!__OpenBSD__) #include <wordexp.h> +#endif #include <stdbool.h> #include <string.h> #include <stdlib.h> @@ -245,6 +247,7 @@ char* offDEFAULTS[22] = { "/.git/off/objects", "copy", "disable", "offNoValue", // helpers ////// +#if (!__OpenBSD__) // expands ~/ char *expandHome(char *p) { wordexp_t exp_result; @@ -259,6 +262,315 @@ char *expandHome(char *p) { wordfree(&exp_result); return(p); } +#else +#define and && +#define or || +#define not ! +#define elif else if +#define TOKENPASTE2(a, b) a ## b +#define TOKENPASTE(a, b) TOKENPASTE2(a, b) +#define UNIQVAR(name) TOKENPASTE(name, __LINE__) +#define forEachS(list, element) \ + ;size_t UNIQVAR(libsheepyInternalIndex) = 0; \ + for (char *element = list[0]; list[UNIQVAR(libsheepyInternalIndex)]!= NULL ; UNIQVAR(libsheepyInternalIndex)++, element = list[UNIQVAR(libsheepyInternalIndex)]) +char *findS(const char *string, const char *needle) { + + // sanity checks + if (!string || !needle) { + return(NULL); + } + return(strstr(string, needle)); +} +char *strLCpy(char *dst, size_t dstSize, const char *src) { + + if (!dst || !src) { + return(NULL); + } + + char *r = strncpy(dst, src, dstSize);; + if (dstSize) { + r[dstSize-1] = 0; + } + return(r); +} +char *strLNCat(char *dst, size_t dstSize, const char *src, size_t srcLen) { + + if (!dst || !src) { + return(NULL); + } + + size_t dL = strnlen(dst, dstSize); + size_t dstLen = dstSize-1; + + if (dL >= dstLen) { + // buffer is full + return(dst); + } + + size_t sL = strnlen(src, srcLen); + + if (dL+sL > dstLen) { + // truncate + return(strncat(dst, src, dstLen - dL)); + } + else { + return(strncat(dst, src, srcLen)); +} + } +#define forEachCharP(list, element) \ + for (char **element=list ; *element != NULL ; element++) +size_t listLengthS(char **list) { + size_t r = 0;; + + // sanity checks + if (!list) { + return(0); + } + forEachCharP(list, i) { + r++; + } + return(r); +} +char **listPushS(char ***list, const char *s) { + + // sanity checks + if (!list) { + return(NULL); + } + + if (!*list) { + *list = malloc(2 * sizeof(char *)); + if (!s) { + (*list)[0] = NULL; + } + else { + (*list)[0] = strdup(s); + } + (*list)[1] = NULL; + } + else { + // realloc list and copy s to last element + size_t len; + len = listLengthS(*list); + char **tmp = realloc(*list, (len+2) * sizeof(char *)); + if (!tmp) { + return(NULL); + } + else { + *list = tmp; + (*list)[len+1] = NULL; + if (!s) { + // s is NULL, add NULL in list + (*list)[len] = NULL; + } + else { + (*list)[len] = strdup(s); + } + } + } + return(*list); +} +#define listEmptyS(list) \ + do {\ + list = malloc(1 * sizeof(char *)); \ + if (list) list[0] = NULL; \ + } while(0); +char **readText(const char *filePath) { + FILE *fp = NULL; + size_t len; + char* line = NULL; + ssize_t read; + char **list = NULL; + + // sanity checks + if (!filePath) { + return(NULL); + } + fp = fopen(filePath, "r"); + if (!fp) { + //pFuncError + //shEPrintfS("The path was: \"%s\"\n", filePath); + return(NULL); + } + // read all lines + read = getline(&line, &len, fp); + while (read != -1) { + { + char* pos = NULL; + pos = strchr(line, '\n'); + if (pos != NULL) + *pos = '\0'; + } + listPushS(&list, line); + read = getline(&line, &len, fp); + } + fclose(fp); + free(line); + if (!list) { + // nothing was read + listEmptyS(list); + } + return(list); +} +bool startsWithS(const char *string1, const char *string2) { + + // sanity checks + if (!string1 || !string2) { + return(false); + } + return(strncmp(string1, string2, strlen(string2)) == 0);; +} +void listFreeS(char **list) { + + // sanity checks + if (list) { + forEachCharP(list, e) { + free(*e); + } + free(list); +} + } +char *iAppendS(char **string1, const char *string2) { + char *tmp = NULL; + size_t l1; + size_t l2; + + if (!string1 || !string2) { + return(NULL); + } + + if (!*string1) { + *string1 = strdup(string2); + return(*string1); + } + + l1 = strlen(*string1); + l2 = strlen(string2); + + if (!l2) { + // empty string + return(*string1); + } + + tmp = realloc(*string1, l1 + l2 + 1); + if (!tmp) { + return(NULL); + } + + *string1 = tmp; + strcat(*string1, string2); + return(*string1); +} +char *expandHome(char *path) { + + // sanity checks + if (!path) { + return(NULL); + } + + + if (path[0] == 0) { + // path is empty + return(path); + } + + // steps + // determine path format + // set user name, either current user or user name in path + // add : at the end of username to match line in the /etc/passwd file + // find home path in the passwd file + + enum {noExpand, currentUser, otherUser}; + + // determine path format + int status = noExpand; + if (path[0] == '~' and (path[1] == '/' or path[1] == 0)) { + // path="~/..." + status = currentUser; + } + elif (path[0] == '~' and path[1] != '/') { + // path="~USER..." + status = otherUser; + } + + // there is no tilde to expand, return path unchanged + if (status == noExpand) { + return(path); + } + + // set user name, either current user or user name in path + char user[33] = {0}; + size_t pathStart = 0; + + if (status == currentUser) { + // use getlogin to find current username + // sizeof(user)-1 to keep a char tp append final ':' + if (getlogin_r(user, sizeof(user)-1)) { + // error + //logE("getlogin for current user"); + } { + pathStart = 1; + } + } + else { + // username is in path + // from index 1 (skip ~) to the first / + char *slash = findS(path, "/"); + if (!slash) { + // no slash found, path is in the form: ~USER + // copy string after ~ to the end of the string + strLCpy(user, sizeof(user)-1, path+1); + pathStart = strlen(path); + } + else { + // copy string after ~ to first slash + pathStart = slash - path; + strLNCat(user, sizeof(user)-1, path+1, pathStart-1); + } + } + + // add : at the end of username to match line in passwd + size_t len = strlen(user); + user[len] = ':'; + user[len+1] = 0; + + + // find home path in the passwd file + char **pwd = readText("/etc/passwd"); + + if (!pwd) { + return(NULL); + } + + // result + char *r = NULL; + + forEachS(pwd, l) { + if (startsWithS(l, user)) { + // found the user + char **l_l = split(l, ":"); + // copy home path to result + r = strdup(l_l[5]); + listFreeS(l_l); + break; + } + } + + listFreeS(pwd); + + if (!r) { + // user not found in this system + return(NULL); + } + + // append rest of the path to the result + iAppendS(&r, path + pathStart); + + free(path); + + return(r); +} +#endif // appends log to git config off.log