#include "quote.h"
#include "hashmap.h"
#include "string-list.h"
+#include "utf8.h"
struct config_source {
struct config_source *prev;
static int config_file_fgetc(struct config_source *conf)
{
- return fgetc(conf->u.file);
+ return getc_unlocked(conf->u.file);
}
static int config_file_ungetc(int c, struct config_source *conf)
static int config_buf_ungetc(int c, struct config_source *conf)
{
- if (conf->u.buf.pos > 0)
- return conf->u.buf.buf[--conf->u.buf.pos];
+ if (conf->u.buf.pos > 0) {
+ conf->u.buf.pos--;
+ if (conf->u.buf.buf[conf->u.buf.pos] != c)
+ die("BUG: config_buf can only ungetc the same character");
+ return c;
+ }
return EOF;
}
/* DOS like systems */
c = cf->do_fgetc(cf);
if (c != '\n') {
- cf->do_ungetc(c, cf);
+ if (c != EOF)
+ cf->do_ungetc(c, cf);
c = '\r';
}
}
struct strbuf *var = &cf->var;
/* U+FEFF Byte Order Mark in UTF8 */
- static const unsigned char *utf8_bom = (unsigned char *) "\xef\xbb\xbf";
- const unsigned char *bomptr = utf8_bom;
+ const char *bomptr = utf8_bom;
for (;;) {
int c = get_next_char();
/* We are at the file beginning; skip UTF8-encoded BOM
* if present. Sane editors won't put this in on their
* own, but e.g. Windows Notepad will do it happily. */
- if ((unsigned char) c == *bomptr) {
+ if (c == (*bomptr & 0377)) {
bomptr++;
continue;
} else {
f = fopen(filename, "r");
if (f) {
+ flockfile(f);
ret = do_config_from_file(fn, filename, filename, f, data);
+ funlockfile(f);
fclose(f);
}
return ret;
int git_config_early(config_fn_t fn, void *data, const char *repo_config)
{
int ret = 0, found = 0;
- char *xdg_config = NULL;
- char *user_config = NULL;
-
- home_config_paths(&user_config, &xdg_config, "config");
+ char *xdg_config = xdg_config_home("config");
+ char *user_config = expand_user_path("~/.gitconfig");
if (git_config_system() && !access_or_die(git_etc_gitconfig(), R_OK, 0)) {
ret += git_config_from_file(fn, git_etc_gitconfig(),
string_list_init(&e->value_list, 1);
hashmap_add(&cs->config_hash, e);
}
- si = string_list_append_nodup(&e->value_list, value ? xstrdup(value) : NULL);
+ si = string_list_append_nodup(&e->value_list, xstrdup_or_null(value));
ALLOC_GROW(cs->list.items, cs->list.nr + 1, cs->list.alloc);
l_item = &cs->list.items[cs->list.nr++];
const char *key, const char *value,
const char *value_regex, int multi_replace)
{
- int fd = -1, in_fd;
+ int fd = -1, in_fd = -1;
int ret;
struct lock_file *lock = NULL;
char *filename_buf = NULL;
+ char *contents = NULL;
+ size_t contents_sz;
/* parse-key returns negative; flip the sign to feed exit(3) */
ret = 0 - git_config_parse_key(key, &store.key, &store.baselen);
goto write_err_out;
} else {
struct stat st;
- char *contents;
- size_t contents_sz, copy_begin, copy_end;
+ size_t copy_begin, copy_end;
int i, new_line = 0;
if (value_regex == NULL)
fstat(in_fd, &st);
contents_sz = xsize_t(st.st_size);
- contents = xmmap(NULL, contents_sz, PROT_READ,
- MAP_PRIVATE, in_fd, 0);
+ contents = xmmap_gently(NULL, contents_sz, PROT_READ,
+ MAP_PRIVATE, in_fd, 0);
+ if (contents == MAP_FAILED) {
+ if (errno == ENODEV && S_ISDIR(st.st_mode))
+ errno = EISDIR;
+ error("unable to mmap '%s': %s",
+ config_filename, strerror(errno));
+ ret = CONFIG_INVALID_FILE;
+ contents = NULL;
+ goto out_free;
+ }
close(in_fd);
+ in_fd = -1;
if (chmod(lock->filename.buf, st.st_mode & 07777) < 0) {
error("chmod on %s failed: %s",
goto write_err_out;
munmap(contents, contents_sz);
+ contents = NULL;
}
if (commit_lock_file(lock) < 0) {
if (lock)
rollback_lock_file(lock);
free(filename_buf);
+ if (contents)
+ munmap(contents, contents_sz);
+ if (in_fd >= 0)
+ close(in_fd);
return ret;
write_err_out: