commit 1d126e2d216c06991bbc586d796b3d002b2bd7d6 from: Stefan Sperling date: Sat Aug 24 19:08:19 2019 UTC add support for reading .git/config; parser was based on isakmpd/conf.c commit - 63c5ca5de411be54e75480b0efec04014ffab46e commit + 1d126e2d216c06991bbc586d796b3d002b2bd7d6 blob - 4d887779da3647bcf38fded4c8db1d120fb3aaaf blob + 8c1fca65ca8a824451198211eb32ae34620b0f8f --- got/Makefile +++ got/Makefile @@ -8,7 +8,7 @@ SRCS= got.c blame.c commit_graph.c delta.c diff.c \ object_idset.c object_parse.c opentemp.c path.c pack.c \ privsep.c reference.c repository.c sha1.c worktree.c \ inflate.c buf.c worklist.c rcsutil.c diff3.c lockfile.c \ - deflate.c object_create.c + deflate.c object_create.c gitconfig.c MAN = ${PROG}.1 got-worktree.5 git-repository.5 CPPFLAGS = -I${.CURDIR}/../include -I${.CURDIR}/../lib blob - /dev/null blob + 754cbc5403b1c92e536fca4f373dea3a300c73d4 (mode 644) --- /dev/null +++ lib/gitconfig.c @@ -0,0 +1,669 @@ +/* $OpenBSD: conf.c,v 1.107 2017/10/27 08:29:32 mpi Exp $ */ +/* $EOM: conf.c,v 1.48 2000/12/04 02:04:29 angelos Exp $ */ + +/* + * Copyright (c) 1998, 1999, 2000, 2001 Niklas Hallqvist. All rights reserved. + * Copyright (c) 2000, 2001, 2002 Håkan Olsson. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "got_error.h" + +#include "got_lib_gitconfig.h" + +#ifndef nitems +#define nitems(_a) (sizeof(_a) / sizeof((_a)[0])) +#endif + +#define LOG_MISC 0 +#define LOG_REPORT 1 +#ifdef GITCONFIG_DEBUG +#define LOG_DBG(x) log_debug x +#else +#define LOG_DBG(x) +#endif + +#define log_print printf +#define log_error printf + +#ifdef GITCONFIG_DEBUG +static void +log_debug(int cls, int level, const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + va_end(ap); +} +#endif + +struct got_gitconfig_trans { + TAILQ_ENTRY(got_gitconfig_trans) link; + int trans; + enum got_gitconfig_op { + CONF_SET, CONF_REMOVE, CONF_REMOVE_SECTION + } op; + char *section; + char *tag; + char *value; + int override; + int is_default; +}; + +TAILQ_HEAD(got_gitconfig_trans_head, got_gitconfig_trans); + +struct got_gitconfig_binding { + LIST_ENTRY(got_gitconfig_binding) link; + char *section; + char *tag; + char *value; + int is_default; +}; + +LIST_HEAD(got_gitconfig_bindings, got_gitconfig_binding); + +struct got_gitconfig { + struct got_gitconfig_bindings bindings[256]; + struct got_gitconfig_trans_head trans_queue; + char *addr; + int seq; +}; + +static __inline__ u_int8_t +conf_hash(char *s) +{ + u_int8_t hash = 0; + + while (*s) { + hash = ((hash << 1) | (hash >> 7)) ^ tolower((unsigned char)*s); + s++; + } + return hash; +} + +/* + * Insert a tag-value combination from LINE (the equal sign is at POS) + */ +static int +conf_remove_now(struct got_gitconfig *conf, char *section, char *tag) +{ + struct got_gitconfig_binding *cb, *next; + + for (cb = LIST_FIRST(&conf->bindings[conf_hash(section)]); cb; + cb = next) { + next = LIST_NEXT(cb, link); + if (strcasecmp(cb->section, section) == 0 && + strcasecmp(cb->tag, tag) == 0) { + LIST_REMOVE(cb, link); + LOG_DBG((LOG_MISC, 95, "[%s]:%s->%s removed", section, + tag, cb->value)); + free(cb->section); + free(cb->tag); + free(cb->value); + free(cb); + return 0; + } + } + return 1; +} + +static int +conf_remove_section_now(struct got_gitconfig *conf, char *section) +{ + struct got_gitconfig_binding *cb, *next; + int unseen = 1; + + for (cb = LIST_FIRST(&conf->bindings[conf_hash(section)]); cb; + cb = next) { + next = LIST_NEXT(cb, link); + if (strcasecmp(cb->section, section) == 0) { + unseen = 0; + LIST_REMOVE(cb, link); + LOG_DBG((LOG_MISC, 95, "[%s]:%s->%s removed", section, + cb->tag, cb->value)); + free(cb->section); + free(cb->tag); + free(cb->value); + free(cb); + } + } + return unseen; +} + +/* + * Insert a tag-value combination from LINE (the equal sign is at POS) + * into SECTION of our configuration database. + */ +static int +conf_set_now(struct got_gitconfig *conf, char *section, char *tag, + char *value, int override, int is_default) +{ + struct got_gitconfig_binding *node = 0; + + if (override) + conf_remove_now(conf, section, tag); + else if (got_gitconfig_get_str(conf, section, tag)) { + if (!is_default) + log_print("conf_set_now: duplicate tag [%s]:%s, " + "ignoring...\n", section, tag); + return 1; + } + node = calloc(1, sizeof *node); + if (!node) { + log_error("conf_set_now: calloc (1, %lu) failed", + (unsigned long)sizeof *node); + return 1; + } + node->section = node->tag = node->value = NULL; + if ((node->section = strdup(section)) == NULL) + goto fail; + if ((node->tag = strdup(tag)) == NULL) + goto fail; + if ((node->value = strdup(value)) == NULL) + goto fail; + node->is_default = is_default; + + LIST_INSERT_HEAD(&conf->bindings[conf_hash(section)], node, link); + LOG_DBG((LOG_MISC, 95, "conf_set_now: [%s]:%s->%s", node->section, + node->tag, node->value)); + return 0; +fail: + free(node->value); + free(node->tag); + free(node->section); + free(node); + return 1; +} + +/* + * Parse the line LINE of SZ bytes. Skip Comments, recognize section + * headers and feed tag-value pairs into our configuration database. + */ +static const struct got_error * +conf_parse_line(char **section, struct got_gitconfig *conf, int trans, + char *line, int ln, size_t sz) +{ + char *val; + size_t i; + int j; + + /* Lines starting with '#' or ';' are comments. */ + if (*line == '#' || *line == ';') + return NULL; + + /* '[section]' parsing... */ + if (*line == '[') { + for (i = 1; i < sz; i++) + if (line[i] == ']') + break; + free(*section); + if (i == sz) { + log_print("conf_parse_line: %d:" + "unmatched ']', ignoring until next section", ln); + *section = NULL; + return NULL; + } + *section = malloc(i); + if (*section == NULL) + return got_error_from_errno("malloc"); + strlcpy(*section, line + 1, i); + return NULL; + } + while (isspace((unsigned char)*line)) + line++; + + /* Deal with assignments. */ + for (i = 0; i < sz; i++) + if (line[i] == '=') { + /* If no section, we are ignoring the lines. */ + if (!*section) { + log_print("conf_parse_line: %d: ignoring line " + "due to no section", ln); + return NULL; + } + line[strcspn(line, " \t=")] = '\0'; + val = line + i + 1 + strspn(line + i + 1, " \t"); + /* Skip trailing whitespace, if any */ + for (j = sz - (val - line) - 1; j > 0 && + isspace((unsigned char)val[j]); j--) + val[j] = '\0'; + /* XXX Perhaps should we not ignore errors? */ + got_gitconfig_set(conf, trans, *section, line, val, + 0, 0); + return NULL; + } + /* Other non-empty lines are weird. */ + i = strspn(line, " \t"); + if (line[i]) + log_print("conf_parse_line: %d: syntax error", ln); + + return NULL; +} + +/* Parse the mapped configuration file. */ +static const struct got_error * +conf_parse(struct got_gitconfig *conf, int trans, char *buf, size_t sz) +{ + const struct got_error *err = NULL; + char *cp = buf; + char *bufend = buf + sz; + char *line, *section = NULL; + int ln = 1; + + line = cp; + while (cp < bufend) { + if (*cp == '\n') { + /* Check for escaped newlines. */ + if (cp > buf && *(cp - 1) == '\\') + *(cp - 1) = *cp = ' '; + else { + *cp = '\0'; + err = conf_parse_line(§ion, conf, trans, + line, ln, cp - line); + if (err) + return err; + line = cp + 1; + } + ln++; + } + cp++; + } + if (cp != line) + log_print("conf_parse: last line unterminated, ignored."); + return NULL; +} + +const struct got_error * +got_gitconfig_open(struct got_gitconfig **conf, const char *gitconfig_path) +{ + unsigned int i; + + *conf = calloc(1, sizeof(**conf)); + if (*conf == NULL) + return got_error_from_errno("malloc"); + + for (i = 0; i < nitems((*conf)->bindings); i++) + LIST_INIT(&(*conf)->bindings[i]); + TAILQ_INIT(&(*conf)->trans_queue); + return got_gitconfig_reinit(*conf, gitconfig_path); +} + +static void +conf_clear(struct got_gitconfig *conf) +{ + struct got_gitconfig_binding *cb; + int i; + + if (conf->addr) { + for (i = 0; i < nitems(conf->bindings); i++) + for (cb = LIST_FIRST(&conf->bindings[i]); cb; + cb = LIST_FIRST(&conf->bindings[i])) + conf_remove_now(conf, cb->section, cb->tag); + free(conf->addr); + conf->addr = NULL; + } +} + +/* Execute all queued operations for this transaction. Cleanup. */ +static int +conf_end(struct got_gitconfig *conf, int transaction, int commit) +{ + struct got_gitconfig_trans *node, *next; + + for (node = TAILQ_FIRST(&conf->trans_queue); node; node = next) { + next = TAILQ_NEXT(node, link); + if (node->trans == transaction) { + if (commit) + switch (node->op) { + case CONF_SET: + conf_set_now(conf, node->section, + node->tag, node->value, + node->override, node->is_default); + break; + case CONF_REMOVE: + conf_remove_now(conf, node->section, + node->tag); + break; + case CONF_REMOVE_SECTION: + conf_remove_section_now(conf, node->section); + break; + default: + log_print("got_gitconfig_end: unknown " + "operation: %d", node->op); + } + TAILQ_REMOVE(&conf->trans_queue, node, link); + free(node->section); + free(node->tag); + free(node->value); + free(node); + } + } + return 0; +} + + +void +got_gitconfig_close(struct got_gitconfig *conf) +{ + conf_clear(conf); + free(conf); +} + +static int +conf_begin(struct got_gitconfig *conf) +{ + return ++conf->seq; +} + +/* Open the config file and map it into our address space, then parse it. */ +const struct got_error * +got_gitconfig_reinit(struct got_gitconfig *conf, const char *gitconfig_path) +{ + const struct got_error *err = NULL; + int fd, trans; + size_t sz; + char *new_conf_addr = 0; + struct stat st; + + fd = open(gitconfig_path, O_RDONLY, 0); + if (fd == -1) { + if (errno != ENOENT) + return got_error_from_errno2("open", gitconfig_path); + return NULL; + } + + if (fstat(fd, &st)) { + err = got_error_from_errno2("fstat", gitconfig_path); + goto fail; + } + + sz = st.st_size; + new_conf_addr = malloc(sz); + if (new_conf_addr == NULL) { + err = got_error_from_errno("malloc"); + goto fail; + } + /* XXX I assume short reads won't happen here. */ + if (read(fd, new_conf_addr, sz) != (int)sz) { + err = got_error_from_errno("read"); + goto fail; + } + close(fd); + fd = -1; + + trans = conf_begin(conf); + + err = conf_parse(conf, trans, new_conf_addr, sz); + if (err) + goto fail; + + /* Free potential existing configuration. */ + conf_clear(conf); + conf_end(conf, trans, 1); + conf->addr = new_conf_addr; + return NULL; + +fail: + free(new_conf_addr); + if (fd != -1) + close(fd); + return err; +} + +/* + * Return the numeric value denoted by TAG in section SECTION or DEF + * if that tag does not exist. + */ +int +got_gitconfig_get_num(struct got_gitconfig *conf, char *section, char *tag, + int def) +{ + char *value = got_gitconfig_get_str(conf, section, tag); + + if (value) + return atoi(value); + return def; +} + +/* Validate X according to the range denoted by TAG in section SECTION. */ +int +got_gitconfig_match_num(struct got_gitconfig *conf, char *section, char *tag, + int x) +{ + char *value = got_gitconfig_get_str(conf, section, tag); + int val, min, max, n; + + if (!value) + return 0; + n = sscanf(value, "%d,%d:%d", &val, &min, &max); + switch (n) { + case 1: + LOG_DBG((LOG_MISC, 95, "got_gitconfig_match_num: %s:%s %d==%d?", + section, tag, val, x)); + return x == val; + case 3: + LOG_DBG((LOG_MISC, 95, "got_gitconfig_match_num: %s:%s %d<=%d<=%d?", + section, tag, min, x, max)); + return min <= x && max >= x; + default: + log_error("got_gitconfig_match_num: section %s tag %s: invalid number " + "spec %s", section, tag, value); + } + return 0; +} + +/* Return the string value denoted by TAG in section SECTION. */ +char * +got_gitconfig_get_str(struct got_gitconfig *conf, char *section, char *tag) +{ + struct got_gitconfig_binding *cb; + + for (cb = LIST_FIRST(&conf->bindings[conf_hash(section)]); cb; + cb = LIST_NEXT(cb, link)) + if (strcasecmp(section, cb->section) == 0 && + strcasecmp(tag, cb->tag) == 0) { + LOG_DBG((LOG_MISC, 95, "got_gitconfig_get_str: [%s]:%s->%s", + section, tag, cb->value)); + return cb->value; + } + LOG_DBG((LOG_MISC, 95, + "got_gitconfig_get_str: configuration value not found [%s]:%s", section, + tag)); + return 0; +} + +/* + * Build a list of string values out of the comma separated value denoted by + * TAG in SECTION. + */ +struct got_gitconfig_list * +got_gitconfig_get_list(struct got_gitconfig *conf, char *section, char *tag) +{ + char *liststr = 0, *p, *field, *t; + struct got_gitconfig_list *list = 0; + struct got_gitconfig_list_node *node = 0; + + list = malloc(sizeof *list); + if (!list) + goto cleanup; + TAILQ_INIT(&list->fields); + list->cnt = 0; + liststr = got_gitconfig_get_str(conf, section, tag); + if (!liststr) + goto cleanup; + liststr = strdup(liststr); + if (!liststr) + goto cleanup; + p = liststr; + while ((field = strsep(&p, ",")) != NULL) { + /* Skip leading whitespace */ + while (isspace((unsigned char)*field)) + field++; + /* Skip trailing whitespace */ + if (p) + for (t = p - 1; t > field && isspace((unsigned char)*t); t--) + *t = '\0'; + if (*field == '\0') { + log_print("got_gitconfig_get_list: empty field, ignoring..."); + continue; + } + list->cnt++; + node = calloc(1, sizeof *node); + if (!node) + goto cleanup; + node->field = strdup(field); + if (!node->field) + goto cleanup; + TAILQ_INSERT_TAIL(&list->fields, node, link); + } + free(liststr); + return list; + +cleanup: + free(node); + if (list) + got_gitconfig_free_list(list); + free(liststr); + return 0; +} + +struct got_gitconfig_list * +got_gitconfig_get_tag_list(struct got_gitconfig *conf, char *section) +{ + struct got_gitconfig_list *list = 0; + struct got_gitconfig_list_node *node = 0; + struct got_gitconfig_binding *cb; + + list = malloc(sizeof *list); + if (!list) + goto cleanup; + TAILQ_INIT(&list->fields); + list->cnt = 0; + for (cb = LIST_FIRST(&conf->bindings[conf_hash(section)]); cb; + cb = LIST_NEXT(cb, link)) + if (strcasecmp(section, cb->section) == 0) { + list->cnt++; + node = calloc(1, sizeof *node); + if (!node) + goto cleanup; + node->field = strdup(cb->tag); + if (!node->field) + goto cleanup; + TAILQ_INSERT_TAIL(&list->fields, node, link); + } + return list; + +cleanup: + free(node); + if (list) + got_gitconfig_free_list(list); + return 0; +} + +void +got_gitconfig_free_list(struct got_gitconfig_list *list) +{ + struct got_gitconfig_list_node *node = TAILQ_FIRST(&list->fields); + + while (node) { + TAILQ_REMOVE(&list->fields, node, link); + free(node->field); + free(node); + node = TAILQ_FIRST(&list->fields); + } + free(list); +} + +static int +got_gitconfig_trans_node(struct got_gitconfig *conf, int transaction, + enum got_gitconfig_op op, char *section, char *tag, char *value, + int override, int is_default) +{ + struct got_gitconfig_trans *node; + + node = calloc(1, sizeof *node); + if (!node) { + log_error("got_gitconfig_trans_node: calloc (1, %lu) failed", + (unsigned long)sizeof *node); + return 1; + } + node->trans = transaction; + node->op = op; + node->override = override; + node->is_default = is_default; + if (section && (node->section = strdup(section)) == NULL) + goto fail; + if (tag && (node->tag = strdup(tag)) == NULL) + goto fail; + if (value && (node->value = strdup(value)) == NULL) + goto fail; + TAILQ_INSERT_TAIL(&conf->trans_queue, node, link); + return 0; + +fail: + free(node->section); + free(node->tag); + free(node->value); + free(node); + return 1; +} + +/* Queue a set operation. */ +int +got_gitconfig_set(struct got_gitconfig *conf, int transaction, char *section, + char *tag, char *value, int override, int is_default) +{ + return got_gitconfig_trans_node(conf, transaction, CONF_SET, section, + tag, value, override, is_default); +} + +/* Queue a remove operation. */ +int +got_gitconfig_remove(struct got_gitconfig *conf, int transaction, + char *section, char *tag) +{ + return got_gitconfig_trans_node(conf, transaction, CONF_REMOVE, + section, tag, NULL, 0, 0); +} + +/* Queue a remove section operation. */ +int +got_gitconfig_remove_section(struct got_gitconfig *conf, int transaction, + char *section) +{ + return got_gitconfig_trans_node(conf, transaction, CONF_REMOVE_SECTION, + section, NULL, NULL, 0, 0); +} blob - /dev/null blob + 828787b0e4bac8fc800346d343d9896bcd3e3801 (mode 644) --- /dev/null +++ lib/got_lib_gitconfig.h @@ -0,0 +1,53 @@ +/* $OpenBSD: conf.h,v 1.34 2006/08/30 16:56:56 hshoexer Exp $ */ +/* $EOM: conf.h,v 1.13 2000/09/18 00:01:47 ho Exp $ */ + +/* + * Copyright (c) 1998, 1999, 2001 Niklas Hallqvist. All rights reserved. + * Copyright (c) 2000, 2003 Håkan Olsson. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +struct got_gitconfig_list_node { + TAILQ_ENTRY(got_gitconfig_list_node) link; + char *field; +}; + +struct got_gitconfig_list { + size_t cnt; + TAILQ_HEAD(got_gitconfig_list_fields_head, got_gitconfig_list_node) fields; +}; + +struct got_gitconfig; + +void got_gitconfig_free_list(struct got_gitconfig_list *); +struct got_gitconfig_list *got_gitconfig_get_list(struct got_gitconfig *, char *, char *); +struct got_gitconfig_list *got_gitconfig_get_tag_list(struct got_gitconfig *, char *); +int got_gitconfig_get_num(struct got_gitconfig *, char *, char *, int); +char *got_gitconfig_get_str(struct got_gitconfig *, char *, char *); +const struct got_error *got_gitconfig_open(struct got_gitconfig **, + const char *); +void got_gitconfig_close(struct got_gitconfig *); +int got_gitconfig_match_num(struct got_gitconfig *, char *, char *, int); +const struct got_error *got_gitconfig_reinit(struct got_gitconfig *, const char *); +int got_gitconfig_remove(struct got_gitconfig *, int, char *, char *); +int got_gitconfig_remove_section(struct got_gitconfig *, int, char *); +int got_gitconfig_set(struct got_gitconfig *, int, char *, char *, char *, int, int); blob - 4379222e6238860a7965b41526f817c2614aa6e5 blob + 23ca2d585f593cbd7176990ce665928bea219089 --- lib/got_lib_repository.h +++ lib/got_lib_repository.h @@ -40,6 +40,9 @@ struct got_repository { struct got_object_cache treecache; struct got_object_cache commitcache; struct got_object_cache tagcache; + + /* Settings read from Git configuration files. */ + struct got_gitconfig *gitconfig; }; const struct got_error*got_repo_cache_object(struct got_repository *, blob - eeffa65542fb24958cb041d67effcdf464713ded blob + f7044b4650178445f7122537b90eeb272ddafe4b --- lib/repository.c +++ lib/repository.c @@ -56,6 +56,7 @@ #include "got_lib_sha1.h" #include "got_lib_object_cache.h" #include "got_lib_repository.h" +#include "got_lib_gitconfig.h" #ifndef nitems #define nitems(_a) (sizeof(_a) / sizeof((_a)[0])) @@ -67,6 +68,7 @@ #define GOT_OBJECTS_DIR "objects" #define GOT_REFS_DIR "refs" #define GOT_HEAD_FILE "HEAD" +#define GOT_GITCONFIG "config" /* Other files and directories inside the git directory. */ #define GOT_FETCH_HEAD_FILE "FETCH_HEAD" @@ -132,6 +134,15 @@ static char * get_path_head(struct got_repository *repo) { return get_path_git_child(repo, GOT_HEAD_FILE); +} + +static const struct got_error * +get_path_gitconfig(char **p, struct got_repository *repo) +{ + *p = get_path_git_child(repo, GOT_GITCONFIG); + if (*p == NULL) + return got_error_from_errno("asprintf"); + return NULL; } static int @@ -330,7 +341,7 @@ got_repo_open(struct got_repository **repop, const cha { struct got_repository *repo = NULL; const struct got_error *err = NULL; - char *abspath; + char *abspath, *gitconfig_path = NULL; int i, tried_root = 0; *repop = NULL; @@ -394,12 +405,25 @@ got_repo_open(struct got_repository **repop, const cha if (path == NULL) err = got_error_from_errno2("dirname", path); } while (path); + + err = get_path_gitconfig(&gitconfig_path, repo); + if (err) + goto done; + +#ifdef notyet + err = got_gitconfig_open(&repo->gitconfig, gitconfig_path); + if (err) + goto done; +#else + repo->gitconfig = NULL; +#endif done: if (err) got_repo_close(repo); else *repop = repo; free(abspath); + free(gitconfig_path); return err; } @@ -443,6 +467,8 @@ got_repo_close(struct got_repository *repo) err == NULL) err = got_error_from_errno("close"); } + if (repo->gitconfig) + got_gitconfig_close(repo->gitconfig); free(repo); return err; blob - 85f9a8965833c7ec25df706646762df09e50327b blob + c4fa14f3feb7a9f4a7b01276e5b724b478cab932 --- tog/Makefile +++ tog/Makefile @@ -8,7 +8,7 @@ SRCS= tog.c blame.c commit_graph.c delta.c diff.c \ object_idset.c object_parse.c opentemp.c path.c pack.c \ privsep.c reference.c repository.c sha1.c worktree.c \ utf8.c inflate.c buf.c worklist.c rcsutil.c diff3.c \ - lockfile.c deflate.c object_create.c + lockfile.c deflate.c object_create.c gitconfig.c MAN = ${PROG}.1 CPPFLAGS = -I${.CURDIR}/../include -I${.CURDIR}/../lib