Merge branch 'ah/send-email-sendmail-alias'
[gitweb.git] / config.c
index 9618aa443dee975c639a31a4ae2b3d55eed06d6e..29fa0121d583d3a77fcc2e8319cc484c317dcca3 100644 (file)
--- a/config.c
+++ b/config.c
@@ -50,7 +50,7 @@ static struct config_set the_config_set;
 
 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)
@@ -74,8 +74,12 @@ static int config_buf_fgetc(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;
 }
@@ -236,7 +240,8 @@ static int get_next_char(void)
                /* 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';
                }
        }
@@ -1083,7 +1088,9 @@ int git_config_from_file(config_fn_t fn, const char *filename, void *data)
 
        f = fopen(filename, "r");
        if (f) {
+               flockfile(f);
                ret = do_config_from_file(fn, filename, filename, f, data);
+               funlockfile(f);
                fclose(f);
        }
        return ret;
@@ -1180,10 +1187,8 @@ int git_config_system(void)
 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(),
@@ -1340,7 +1345,7 @@ static int configset_add_value(struct config_set *cs, const char *key, const cha
                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++];
@@ -1934,6 +1939,8 @@ int git_config_set_multivar_in_file(const char *config_filename,
        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);
@@ -1983,8 +1990,7 @@ int git_config_set_multivar_in_file(const char *config_filename,
                        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)
@@ -2047,8 +2053,17 @@ int git_config_set_multivar_in_file(const char *config_filename,
 
                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);
 
                if (chmod(lock->filename.buf, st.st_mode & 07777) < 0) {
@@ -2103,8 +2118,6 @@ int git_config_set_multivar_in_file(const char *config_filename,
                                          contents_sz - copy_begin) <
                            contents_sz - copy_begin)
                                goto write_err_out;
-
-               munmap(contents, contents_sz);
        }
 
        if (commit_lock_file(lock) < 0) {
@@ -2130,6 +2143,8 @@ int git_config_set_multivar_in_file(const char *config_filename,
        if (lock)
                rollback_lock_file(lock);
        free(filename_buf);
+       if (contents)
+               munmap(contents, contents_sz);
        return ret;
 
 write_err_out: