config.con commit Merge branch 'rs/pretty-safety' (49e6be5)
   1/*
   2 * GIT - The information manager from hell
   3 *
   4 * Copyright (C) Linus Torvalds, 2005
   5 * Copyright (C) Johannes Schindelin, 2005
   6 *
   7 */
   8#include "cache.h"
   9#include "exec_cmd.h"
  10
  11#define MAXNAME (256)
  12
  13static FILE *config_file;
  14static const char *config_file_name;
  15static int config_linenr;
  16static int zlib_compression_seen;
  17
  18static int get_next_char(void)
  19{
  20        int c;
  21        FILE *f;
  22
  23        c = '\n';
  24        if ((f = config_file) != NULL) {
  25                c = fgetc(f);
  26                if (c == '\r') {
  27                        /* DOS like systems */
  28                        c = fgetc(f);
  29                        if (c != '\n') {
  30                                ungetc(c, f);
  31                                c = '\r';
  32                        }
  33                }
  34                if (c == '\n')
  35                        config_linenr++;
  36                if (c == EOF) {
  37                        config_file = NULL;
  38                        c = '\n';
  39                }
  40        }
  41        return c;
  42}
  43
  44static char *parse_value(void)
  45{
  46        static char value[1024];
  47        int quote = 0, comment = 0, len = 0, space = 0;
  48
  49        for (;;) {
  50                int c = get_next_char();
  51                if (len >= sizeof(value))
  52                        return NULL;
  53                if (c == '\n') {
  54                        if (quote)
  55                                return NULL;
  56                        value[len] = 0;
  57                        return value;
  58                }
  59                if (comment)
  60                        continue;
  61                if (isspace(c) && !quote) {
  62                        space = 1;
  63                        continue;
  64                }
  65                if (!quote) {
  66                        if (c == ';' || c == '#') {
  67                                comment = 1;
  68                                continue;
  69                        }
  70                }
  71                if (space) {
  72                        if (len)
  73                                value[len++] = ' ';
  74                        space = 0;
  75                }
  76                if (c == '\\') {
  77                        c = get_next_char();
  78                        switch (c) {
  79                        case '\n':
  80                                continue;
  81                        case 't':
  82                                c = '\t';
  83                                break;
  84                        case 'b':
  85                                c = '\b';
  86                                break;
  87                        case 'n':
  88                                c = '\n';
  89                                break;
  90                        /* Some characters escape as themselves */
  91                        case '\\': case '"':
  92                                break;
  93                        /* Reject unknown escape sequences */
  94                        default:
  95                                return NULL;
  96                        }
  97                        value[len++] = c;
  98                        continue;
  99                }
 100                if (c == '"') {
 101                        quote = 1-quote;
 102                        continue;
 103                }
 104                value[len++] = c;
 105        }
 106}
 107
 108static inline int iskeychar(int c)
 109{
 110        return isalnum(c) || c == '-';
 111}
 112
 113static int get_value(config_fn_t fn, char *name, unsigned int len)
 114{
 115        int c;
 116        char *value;
 117
 118        /* Get the full name */
 119        for (;;) {
 120                c = get_next_char();
 121                if (c == EOF)
 122                        break;
 123                if (!iskeychar(c))
 124                        break;
 125                name[len++] = tolower(c);
 126                if (len >= MAXNAME)
 127                        return -1;
 128        }
 129        name[len] = 0;
 130        while (c == ' ' || c == '\t')
 131                c = get_next_char();
 132
 133        value = NULL;
 134        if (c != '\n') {
 135                if (c != '=')
 136                        return -1;
 137                value = parse_value();
 138                if (!value)
 139                        return -1;
 140        }
 141        return fn(name, value);
 142}
 143
 144static int get_extended_base_var(char *name, int baselen, int c)
 145{
 146        do {
 147                if (c == '\n')
 148                        return -1;
 149                c = get_next_char();
 150        } while (isspace(c));
 151
 152        /* We require the format to be '[base "extension"]' */
 153        if (c != '"')
 154                return -1;
 155        name[baselen++] = '.';
 156
 157        for (;;) {
 158                int c = get_next_char();
 159                if (c == '\n')
 160                        return -1;
 161                if (c == '"')
 162                        break;
 163                if (c == '\\') {
 164                        c = get_next_char();
 165                        if (c == '\n')
 166                                return -1;
 167                }
 168                name[baselen++] = c;
 169                if (baselen > MAXNAME / 2)
 170                        return -1;
 171        }
 172
 173        /* Final ']' */
 174        if (get_next_char() != ']')
 175                return -1;
 176        return baselen;
 177}
 178
 179static int get_base_var(char *name)
 180{
 181        int baselen = 0;
 182
 183        for (;;) {
 184                int c = get_next_char();
 185                if (c == EOF)
 186                        return -1;
 187                if (c == ']')
 188                        return baselen;
 189                if (isspace(c))
 190                        return get_extended_base_var(name, baselen, c);
 191                if (!iskeychar(c) && c != '.')
 192                        return -1;
 193                if (baselen > MAXNAME / 2)
 194                        return -1;
 195                name[baselen++] = tolower(c);
 196        }
 197}
 198
 199static int git_parse_file(config_fn_t fn)
 200{
 201        int comment = 0;
 202        int baselen = 0;
 203        static char var[MAXNAME];
 204
 205        for (;;) {
 206                int c = get_next_char();
 207                if (c == '\n') {
 208                        /* EOF? */
 209                        if (!config_file)
 210                                return 0;
 211                        comment = 0;
 212                        continue;
 213                }
 214                if (comment || isspace(c))
 215                        continue;
 216                if (c == '#' || c == ';') {
 217                        comment = 1;
 218                        continue;
 219                }
 220                if (c == '[') {
 221                        baselen = get_base_var(var);
 222                        if (baselen <= 0)
 223                                break;
 224                        var[baselen++] = '.';
 225                        var[baselen] = 0;
 226                        continue;
 227                }
 228                if (!isalpha(c))
 229                        break;
 230                var[baselen] = tolower(c);
 231                if (get_value(fn, var, baselen+1) < 0)
 232                        break;
 233        }
 234        die("bad config file line %d in %s", config_linenr, config_file_name);
 235}
 236
 237static int parse_unit_factor(const char *end, unsigned long *val)
 238{
 239        if (!*end)
 240                return 1;
 241        else if (!strcasecmp(end, "k")) {
 242                *val *= 1024;
 243                return 1;
 244        }
 245        else if (!strcasecmp(end, "m")) {
 246                *val *= 1024 * 1024;
 247                return 1;
 248        }
 249        else if (!strcasecmp(end, "g")) {
 250                *val *= 1024 * 1024 * 1024;
 251                return 1;
 252        }
 253        return 0;
 254}
 255
 256int git_parse_long(const char *value, long *ret)
 257{
 258        if (value && *value) {
 259                char *end;
 260                long val = strtol(value, &end, 0);
 261                unsigned long factor = 1;
 262                if (!parse_unit_factor(end, &factor))
 263                        return 0;
 264                *ret = val * factor;
 265                return 1;
 266        }
 267        return 0;
 268}
 269
 270int git_parse_ulong(const char *value, unsigned long *ret)
 271{
 272        if (value && *value) {
 273                char *end;
 274                unsigned long val = strtoul(value, &end, 0);
 275                if (!parse_unit_factor(end, &val))
 276                        return 0;
 277                *ret = val;
 278                return 1;
 279        }
 280        return 0;
 281}
 282
 283int git_config_int(const char *name, const char *value)
 284{
 285        long ret;
 286        if (!git_parse_long(value, &ret))
 287                die("bad config value for '%s' in %s", name, config_file_name);
 288        return ret;
 289}
 290
 291unsigned long git_config_ulong(const char *name, const char *value)
 292{
 293        unsigned long ret;
 294        if (!git_parse_ulong(value, &ret))
 295                die("bad config value for '%s' in %s", name, config_file_name);
 296        return ret;
 297}
 298
 299int git_config_bool(const char *name, const char *value)
 300{
 301        if (!value)
 302                return 1;
 303        if (!*value)
 304                return 0;
 305        if (!strcasecmp(value, "true") || !strcasecmp(value, "yes"))
 306                return 1;
 307        if (!strcasecmp(value, "false") || !strcasecmp(value, "no"))
 308                return 0;
 309        return git_config_int(name, value) != 0;
 310}
 311
 312int git_default_config(const char *var, const char *value)
 313{
 314        /* This needs a better name */
 315        if (!strcmp(var, "core.filemode")) {
 316                trust_executable_bit = git_config_bool(var, value);
 317                return 0;
 318        }
 319
 320        if (!strcmp(var, "core.quotepath")) {
 321                quote_path_fully = git_config_bool(var, value);
 322                return 0;
 323        }
 324
 325        if (!strcmp(var, "core.symlinks")) {
 326                has_symlinks = git_config_bool(var, value);
 327                return 0;
 328        }
 329
 330        if (!strcmp(var, "core.bare")) {
 331                is_bare_repository_cfg = git_config_bool(var, value);
 332                return 0;
 333        }
 334
 335        if (!strcmp(var, "core.ignorestat")) {
 336                assume_unchanged = git_config_bool(var, value);
 337                return 0;
 338        }
 339
 340        if (!strcmp(var, "core.prefersymlinkrefs")) {
 341                prefer_symlink_refs = git_config_bool(var, value);
 342                return 0;
 343        }
 344
 345        if (!strcmp(var, "core.logallrefupdates")) {
 346                log_all_ref_updates = git_config_bool(var, value);
 347                return 0;
 348        }
 349
 350        if (!strcmp(var, "core.warnambiguousrefs")) {
 351                warn_ambiguous_refs = git_config_bool(var, value);
 352                return 0;
 353        }
 354
 355        if (!strcmp(var, "core.loosecompression")) {
 356                int level = git_config_int(var, value);
 357                if (level == -1)
 358                        level = Z_DEFAULT_COMPRESSION;
 359                else if (level < 0 || level > Z_BEST_COMPRESSION)
 360                        die("bad zlib compression level %d", level);
 361                zlib_compression_level = level;
 362                zlib_compression_seen = 1;
 363                return 0;
 364        }
 365
 366        if (!strcmp(var, "core.compression")) {
 367                int level = git_config_int(var, value);
 368                if (level == -1)
 369                        level = Z_DEFAULT_COMPRESSION;
 370                else if (level < 0 || level > Z_BEST_COMPRESSION)
 371                        die("bad zlib compression level %d", level);
 372                core_compression_level = level;
 373                core_compression_seen = 1;
 374                if (!zlib_compression_seen)
 375                        zlib_compression_level = level;
 376                return 0;
 377        }
 378
 379        if (!strcmp(var, "core.packedgitwindowsize")) {
 380                int pgsz_x2 = getpagesize() * 2;
 381                packed_git_window_size = git_config_int(var, value);
 382
 383                /* This value must be multiple of (pagesize * 2) */
 384                packed_git_window_size /= pgsz_x2;
 385                if (packed_git_window_size < 1)
 386                        packed_git_window_size = 1;
 387                packed_git_window_size *= pgsz_x2;
 388                return 0;
 389        }
 390
 391        if (!strcmp(var, "core.packedgitlimit")) {
 392                packed_git_limit = git_config_int(var, value);
 393                return 0;
 394        }
 395
 396        if (!strcmp(var, "core.deltabasecachelimit")) {
 397                delta_base_cache_limit = git_config_int(var, value);
 398                return 0;
 399        }
 400
 401        if (!strcmp(var, "core.autocrlf")) {
 402                if (value && !strcasecmp(value, "input")) {
 403                        auto_crlf = -1;
 404                        return 0;
 405                }
 406                auto_crlf = git_config_bool(var, value);
 407                return 0;
 408        }
 409
 410        if (!strcmp(var, "user.name")) {
 411                strlcpy(git_default_name, value, sizeof(git_default_name));
 412                return 0;
 413        }
 414
 415        if (!strcmp(var, "user.email")) {
 416                strlcpy(git_default_email, value, sizeof(git_default_email));
 417                return 0;
 418        }
 419
 420        if (!strcmp(var, "i18n.commitencoding")) {
 421                git_commit_encoding = xstrdup(value);
 422                return 0;
 423        }
 424
 425        if (!strcmp(var, "i18n.logoutputencoding")) {
 426                git_log_output_encoding = xstrdup(value);
 427                return 0;
 428        }
 429
 430
 431        if (!strcmp(var, "pager.color") || !strcmp(var, "color.pager")) {
 432                pager_use_color = git_config_bool(var,value);
 433                return 0;
 434        }
 435
 436        if (!strcmp(var, "core.pager")) {
 437                pager_program = xstrdup(value);
 438                return 0;
 439        }
 440
 441        if (!strcmp(var, "core.editor")) {
 442                editor_program = xstrdup(value);
 443                return 0;
 444        }
 445
 446        if (!strcmp(var, "core.excludesfile")) {
 447                if (!value)
 448                        die("core.excludesfile without value");
 449                excludes_file = xstrdup(value);
 450                return 0;
 451        }
 452
 453        if (!strcmp(var, "core.whitespace")) {
 454                whitespace_rule_cfg = parse_whitespace_rule(value);
 455                return 0;
 456        }
 457
 458        /* Add other config variables here and to Documentation/config.txt. */
 459        return 0;
 460}
 461
 462int git_config_from_file(config_fn_t fn, const char *filename)
 463{
 464        int ret;
 465        FILE *f = fopen(filename, "r");
 466
 467        ret = -1;
 468        if (f) {
 469                config_file = f;
 470                config_file_name = filename;
 471                config_linenr = 1;
 472                ret = git_parse_file(fn);
 473                fclose(f);
 474                config_file_name = NULL;
 475        }
 476        return ret;
 477}
 478
 479const char *git_etc_gitconfig(void)
 480{
 481        static const char *system_wide;
 482        if (!system_wide) {
 483                system_wide = ETC_GITCONFIG;
 484                if (!is_absolute_path(system_wide)) {
 485                        /* interpret path relative to exec-dir */
 486                        const char *exec_path = git_exec_path();
 487                        system_wide = prefix_path(exec_path, strlen(exec_path),
 488                                                system_wide);
 489                }
 490        }
 491        return system_wide;
 492}
 493
 494int git_config(config_fn_t fn)
 495{
 496        int ret = 0;
 497        char *repo_config = NULL;
 498        const char *home = NULL, *filename;
 499
 500        /* $GIT_CONFIG makes git read _only_ the given config file,
 501         * $GIT_CONFIG_LOCAL will make it process it in addition to the
 502         * global config file, the same way it would the per-repository
 503         * config file otherwise. */
 504        filename = getenv(CONFIG_ENVIRONMENT);
 505        if (!filename) {
 506                if (!access(git_etc_gitconfig(), R_OK))
 507                        ret += git_config_from_file(fn, git_etc_gitconfig());
 508                home = getenv("HOME");
 509                filename = getenv(CONFIG_LOCAL_ENVIRONMENT);
 510                if (!filename)
 511                        filename = repo_config = xstrdup(git_path("config"));
 512        }
 513
 514        if (home) {
 515                char *user_config = xstrdup(mkpath("%s/.gitconfig", home));
 516                if (!access(user_config, R_OK))
 517                        ret = git_config_from_file(fn, user_config);
 518                free(user_config);
 519        }
 520
 521        ret += git_config_from_file(fn, filename);
 522        free(repo_config);
 523        return ret;
 524}
 525
 526/*
 527 * Find all the stuff for git_config_set() below.
 528 */
 529
 530#define MAX_MATCHES 512
 531
 532static struct {
 533        int baselen;
 534        char* key;
 535        int do_not_match;
 536        regex_t* value_regex;
 537        int multi_replace;
 538        size_t offset[MAX_MATCHES];
 539        enum { START, SECTION_SEEN, SECTION_END_SEEN, KEY_SEEN } state;
 540        int seen;
 541} store;
 542
 543static int matches(const char* key, const char* value)
 544{
 545        return !strcmp(key, store.key) &&
 546                (store.value_regex == NULL ||
 547                 (store.do_not_match ^
 548                  !regexec(store.value_regex, value, 0, NULL, 0)));
 549}
 550
 551static int store_aux(const char* key, const char* value)
 552{
 553        const char *ep;
 554        size_t section_len;
 555
 556        switch (store.state) {
 557        case KEY_SEEN:
 558                if (matches(key, value)) {
 559                        if (store.seen == 1 && store.multi_replace == 0) {
 560                                fprintf(stderr,
 561                                        "Warning: %s has multiple values\n",
 562                                        key);
 563                        } else if (store.seen >= MAX_MATCHES) {
 564                                fprintf(stderr, "Too many matches\n");
 565                                return 1;
 566                        }
 567
 568                        store.offset[store.seen] = ftell(config_file);
 569                        store.seen++;
 570                }
 571                break;
 572        case SECTION_SEEN:
 573                /*
 574                 * What we are looking for is in store.key (both
 575                 * section and var), and its section part is baselen
 576                 * long.  We found key (again, both section and var).
 577                 * We would want to know if this key is in the same
 578                 * section as what we are looking for.  We already
 579                 * know we are in the same section as what should
 580                 * hold store.key.
 581                 */
 582                ep = strrchr(key, '.');
 583                section_len = ep - key;
 584
 585                if ((section_len != store.baselen) ||
 586                    memcmp(key, store.key, section_len+1)) {
 587                        store.state = SECTION_END_SEEN;
 588                        break;
 589                }
 590
 591                /*
 592                 * Do not increment matches: this is no match, but we
 593                 * just made sure we are in the desired section.
 594                 */
 595                store.offset[store.seen] = ftell(config_file);
 596                /* fallthru */
 597        case SECTION_END_SEEN:
 598        case START:
 599                if (matches(key, value)) {
 600                        store.offset[store.seen] = ftell(config_file);
 601                        store.state = KEY_SEEN;
 602                        store.seen++;
 603                } else {
 604                        if (strrchr(key, '.') - key == store.baselen &&
 605                              !strncmp(key, store.key, store.baselen)) {
 606                                        store.state = SECTION_SEEN;
 607                                        store.offset[store.seen] = ftell(config_file);
 608                        }
 609                }
 610        }
 611        return 0;
 612}
 613
 614static int write_error(void)
 615{
 616        fprintf(stderr, "Failed to write new configuration file\n");
 617
 618        /* Same error code as "failed to rename". */
 619        return 4;
 620}
 621
 622static int store_write_section(int fd, const char* key)
 623{
 624        const char *dot;
 625        int i, success;
 626        struct strbuf sb;
 627
 628        strbuf_init(&sb, 0);
 629        dot = memchr(key, '.', store.baselen);
 630        if (dot) {
 631                strbuf_addf(&sb, "[%.*s \"", (int)(dot - key), key);
 632                for (i = dot - key + 1; i < store.baselen; i++) {
 633                        if (key[i] == '"')
 634                                strbuf_addch(&sb, '\\');
 635                        strbuf_addch(&sb, key[i]);
 636                }
 637                strbuf_addstr(&sb, "\"]\n");
 638        } else {
 639                strbuf_addf(&sb, "[%.*s]\n", store.baselen, key);
 640        }
 641
 642        success = write_in_full(fd, sb.buf, sb.len) == sb.len;
 643        strbuf_release(&sb);
 644
 645        return success;
 646}
 647
 648static int store_write_pair(int fd, const char* key, const char* value)
 649{
 650        int i, success;
 651        int length = strlen(key + store.baselen + 1);
 652        const char *quote = "";
 653        struct strbuf sb;
 654
 655        /*
 656         * Check to see if the value needs to be surrounded with a dq pair.
 657         * Note that problematic characters are always backslash-quoted; this
 658         * check is about not losing leading or trailing SP and strings that
 659         * follow beginning-of-comment characters (i.e. ';' and '#') by the
 660         * configuration parser.
 661         */
 662        if (value[0] == ' ')
 663                quote = "\"";
 664        for (i = 0; value[i]; i++)
 665                if (value[i] == ';' || value[i] == '#')
 666                        quote = "\"";
 667        if (i && value[i - 1] == ' ')
 668                quote = "\"";
 669
 670        strbuf_init(&sb, 0);
 671        strbuf_addf(&sb, "\t%.*s = %s",
 672                    length, key + store.baselen + 1, quote);
 673
 674        for (i = 0; value[i]; i++)
 675                switch (value[i]) {
 676                case '\n':
 677                        strbuf_addstr(&sb, "\\n");
 678                        break;
 679                case '\t':
 680                        strbuf_addstr(&sb, "\\t");
 681                        break;
 682                case '"':
 683                case '\\':
 684                        strbuf_addch(&sb, '\\');
 685                default:
 686                        strbuf_addch(&sb, value[i]);
 687                        break;
 688                }
 689        strbuf_addf(&sb, "%s\n", quote);
 690
 691        success = write_in_full(fd, sb.buf, sb.len) == sb.len;
 692        strbuf_release(&sb);
 693
 694        return success;
 695}
 696
 697static ssize_t find_beginning_of_line(const char* contents, size_t size,
 698        size_t offset_, int* found_bracket)
 699{
 700        size_t equal_offset = size, bracket_offset = size;
 701        ssize_t offset;
 702
 703        for (offset = offset_-2; offset > 0
 704                        && contents[offset] != '\n'; offset--)
 705                switch (contents[offset]) {
 706                        case '=': equal_offset = offset; break;
 707                        case ']': bracket_offset = offset; break;
 708                }
 709        if (bracket_offset < equal_offset) {
 710                *found_bracket = 1;
 711                offset = bracket_offset+1;
 712        } else
 713                offset++;
 714
 715        return offset;
 716}
 717
 718int git_config_set(const char* key, const char* value)
 719{
 720        return git_config_set_multivar(key, value, NULL, 0);
 721}
 722
 723/*
 724 * If value==NULL, unset in (remove from) config,
 725 * if value_regex!=NULL, disregard key/value pairs where value does not match.
 726 * if multi_replace==0, nothing, or only one matching key/value is replaced,
 727 *     else all matching key/values (regardless how many) are removed,
 728 *     before the new pair is written.
 729 *
 730 * Returns 0 on success.
 731 *
 732 * This function does this:
 733 *
 734 * - it locks the config file by creating ".git/config.lock"
 735 *
 736 * - it then parses the config using store_aux() as validator to find
 737 *   the position on the key/value pair to replace. If it is to be unset,
 738 *   it must be found exactly once.
 739 *
 740 * - the config file is mmap()ed and the part before the match (if any) is
 741 *   written to the lock file, then the changed part and the rest.
 742 *
 743 * - the config file is removed and the lock file rename()d to it.
 744 *
 745 */
 746int git_config_set_multivar(const char* key, const char* value,
 747        const char* value_regex, int multi_replace)
 748{
 749        int i, dot;
 750        int fd = -1, in_fd;
 751        int ret;
 752        char* config_filename;
 753        struct lock_file *lock = NULL;
 754        const char* last_dot = strrchr(key, '.');
 755
 756        config_filename = getenv(CONFIG_ENVIRONMENT);
 757        if (!config_filename) {
 758                config_filename = getenv(CONFIG_LOCAL_ENVIRONMENT);
 759                if (!config_filename)
 760                        config_filename  = git_path("config");
 761        }
 762        config_filename = xstrdup(config_filename);
 763
 764        /*
 765         * Since "key" actually contains the section name and the real
 766         * key name separated by a dot, we have to know where the dot is.
 767         */
 768
 769        if (last_dot == NULL) {
 770                fprintf(stderr, "key does not contain a section: %s\n", key);
 771                ret = 2;
 772                goto out_free;
 773        }
 774        store.baselen = last_dot - key;
 775
 776        store.multi_replace = multi_replace;
 777
 778        /*
 779         * Validate the key and while at it, lower case it for matching.
 780         */
 781        store.key = xmalloc(strlen(key) + 1);
 782        dot = 0;
 783        for (i = 0; key[i]; i++) {
 784                unsigned char c = key[i];
 785                if (c == '.')
 786                        dot = 1;
 787                /* Leave the extended basename untouched.. */
 788                if (!dot || i > store.baselen) {
 789                        if (!iskeychar(c) || (i == store.baselen+1 && !isalpha(c))) {
 790                                fprintf(stderr, "invalid key: %s\n", key);
 791                                free(store.key);
 792                                ret = 1;
 793                                goto out_free;
 794                        }
 795                        c = tolower(c);
 796                } else if (c == '\n') {
 797                        fprintf(stderr, "invalid key (newline): %s\n", key);
 798                        free(store.key);
 799                        ret = 1;
 800                        goto out_free;
 801                }
 802                store.key[i] = c;
 803        }
 804        store.key[i] = 0;
 805
 806        /*
 807         * The lock serves a purpose in addition to locking: the new
 808         * contents of .git/config will be written into it.
 809         */
 810        lock = xcalloc(sizeof(struct lock_file), 1);
 811        fd = hold_lock_file_for_update(lock, config_filename, 0);
 812        if (fd < 0) {
 813                fprintf(stderr, "could not lock config file\n");
 814                free(store.key);
 815                ret = -1;
 816                goto out_free;
 817        }
 818
 819        /*
 820         * If .git/config does not exist yet, write a minimal version.
 821         */
 822        in_fd = open(config_filename, O_RDONLY);
 823        if ( in_fd < 0 ) {
 824                free(store.key);
 825
 826                if ( ENOENT != errno ) {
 827                        error("opening %s: %s", config_filename,
 828                              strerror(errno));
 829                        ret = 3; /* same as "invalid config file" */
 830                        goto out_free;
 831                }
 832                /* if nothing to unset, error out */
 833                if (value == NULL) {
 834                        ret = 5;
 835                        goto out_free;
 836                }
 837
 838                store.key = (char*)key;
 839                if (!store_write_section(fd, key) ||
 840                    !store_write_pair(fd, key, value))
 841                        goto write_err_out;
 842        } else {
 843                struct stat st;
 844                char* contents;
 845                size_t contents_sz, copy_begin, copy_end;
 846                int i, new_line = 0;
 847
 848                if (value_regex == NULL)
 849                        store.value_regex = NULL;
 850                else {
 851                        if (value_regex[0] == '!') {
 852                                store.do_not_match = 1;
 853                                value_regex++;
 854                        } else
 855                                store.do_not_match = 0;
 856
 857                        store.value_regex = (regex_t*)xmalloc(sizeof(regex_t));
 858                        if (regcomp(store.value_regex, value_regex,
 859                                        REG_EXTENDED)) {
 860                                fprintf(stderr, "Invalid pattern: %s\n",
 861                                        value_regex);
 862                                free(store.value_regex);
 863                                ret = 6;
 864                                goto out_free;
 865                        }
 866                }
 867
 868                store.offset[0] = 0;
 869                store.state = START;
 870                store.seen = 0;
 871
 872                /*
 873                 * After this, store.offset will contain the *end* offset
 874                 * of the last match, or remain at 0 if no match was found.
 875                 * As a side effect, we make sure to transform only a valid
 876                 * existing config file.
 877                 */
 878                if (git_config_from_file(store_aux, config_filename)) {
 879                        fprintf(stderr, "invalid config file\n");
 880                        free(store.key);
 881                        if (store.value_regex != NULL) {
 882                                regfree(store.value_regex);
 883                                free(store.value_regex);
 884                        }
 885                        ret = 3;
 886                        goto out_free;
 887                }
 888
 889                free(store.key);
 890                if (store.value_regex != NULL) {
 891                        regfree(store.value_regex);
 892                        free(store.value_regex);
 893                }
 894
 895                /* if nothing to unset, or too many matches, error out */
 896                if ((store.seen == 0 && value == NULL) ||
 897                                (store.seen > 1 && multi_replace == 0)) {
 898                        ret = 5;
 899                        goto out_free;
 900                }
 901
 902                fstat(in_fd, &st);
 903                contents_sz = xsize_t(st.st_size);
 904                contents = xmmap(NULL, contents_sz, PROT_READ,
 905                        MAP_PRIVATE, in_fd, 0);
 906                close(in_fd);
 907
 908                if (store.seen == 0)
 909                        store.seen = 1;
 910
 911                for (i = 0, copy_begin = 0; i < store.seen; i++) {
 912                        if (store.offset[i] == 0) {
 913                                store.offset[i] = copy_end = contents_sz;
 914                        } else if (store.state != KEY_SEEN) {
 915                                copy_end = store.offset[i];
 916                        } else
 917                                copy_end = find_beginning_of_line(
 918                                        contents, contents_sz,
 919                                        store.offset[i]-2, &new_line);
 920
 921                        /* write the first part of the config */
 922                        if (copy_end > copy_begin) {
 923                                if (write_in_full(fd, contents + copy_begin,
 924                                                  copy_end - copy_begin) <
 925                                    copy_end - copy_begin)
 926                                        goto write_err_out;
 927                                if (new_line &&
 928                                    write_in_full(fd, "\n", 1) != 1)
 929                                        goto write_err_out;
 930                        }
 931                        copy_begin = store.offset[i];
 932                }
 933
 934                /* write the pair (value == NULL means unset) */
 935                if (value != NULL) {
 936                        if (store.state == START) {
 937                                if (!store_write_section(fd, key))
 938                                        goto write_err_out;
 939                        }
 940                        if (!store_write_pair(fd, key, value))
 941                                goto write_err_out;
 942                }
 943
 944                /* write the rest of the config */
 945                if (copy_begin < contents_sz)
 946                        if (write_in_full(fd, contents + copy_begin,
 947                                          contents_sz - copy_begin) <
 948                            contents_sz - copy_begin)
 949                                goto write_err_out;
 950
 951                munmap(contents, contents_sz);
 952        }
 953
 954        if (close(fd) || commit_lock_file(lock) < 0) {
 955                fprintf(stderr, "Cannot commit config file!\n");
 956                ret = 4;
 957                goto out_free;
 958        }
 959
 960        /* fd is closed, so don't try to close it below. */
 961        fd = -1;
 962        /*
 963         * lock is committed, so don't try to roll it back below.
 964         * NOTE: Since lockfile.c keeps a linked list of all created
 965         * lock_file structures, it isn't safe to free(lock).  It's
 966         * better to just leave it hanging around.
 967         */
 968        lock = NULL;
 969        ret = 0;
 970
 971out_free:
 972        if (0 <= fd)
 973                close(fd);
 974        if (lock)
 975                rollback_lock_file(lock);
 976        free(config_filename);
 977        return ret;
 978
 979write_err_out:
 980        ret = write_error();
 981        goto out_free;
 982
 983}
 984
 985static int section_name_match (const char *buf, const char *name)
 986{
 987        int i = 0, j = 0, dot = 0;
 988        for (; buf[i] && buf[i] != ']'; i++) {
 989                if (!dot && isspace(buf[i])) {
 990                        dot = 1;
 991                        if (name[j++] != '.')
 992                                break;
 993                        for (i++; isspace(buf[i]); i++)
 994                                ; /* do nothing */
 995                        if (buf[i] != '"')
 996                                break;
 997                        continue;
 998                }
 999                if (buf[i] == '\\' && dot)
1000                        i++;
1001                else if (buf[i] == '"' && dot) {
1002                        for (i++; isspace(buf[i]); i++)
1003                                ; /* do_nothing */
1004                        break;
1005                }
1006                if (buf[i] != name[j++])
1007                        break;
1008        }
1009        return (buf[i] == ']' && name[j] == 0);
1010}
1011
1012/* if new_name == NULL, the section is removed instead */
1013int git_config_rename_section(const char *old_name, const char *new_name)
1014{
1015        int ret = 0, remove = 0;
1016        char *config_filename;
1017        struct lock_file *lock = xcalloc(sizeof(struct lock_file), 1);
1018        int out_fd;
1019        char buf[1024];
1020
1021        config_filename = getenv(CONFIG_ENVIRONMENT);
1022        if (!config_filename) {
1023                config_filename = getenv(CONFIG_LOCAL_ENVIRONMENT);
1024                if (!config_filename)
1025                        config_filename  = git_path("config");
1026        }
1027        config_filename = xstrdup(config_filename);
1028        out_fd = hold_lock_file_for_update(lock, config_filename, 0);
1029        if (out_fd < 0) {
1030                ret = error("Could not lock config file!");
1031                goto out;
1032        }
1033
1034        if (!(config_file = fopen(config_filename, "rb"))) {
1035                /* no config file means nothing to rename, no error */
1036                goto unlock_and_out;
1037        }
1038
1039        while (fgets(buf, sizeof(buf), config_file)) {
1040                int i;
1041                int length;
1042                for (i = 0; buf[i] && isspace(buf[i]); i++)
1043                        ; /* do nothing */
1044                if (buf[i] == '[') {
1045                        /* it's a section */
1046                        if (section_name_match (&buf[i+1], old_name)) {
1047                                ret++;
1048                                if (new_name == NULL) {
1049                                        remove = 1;
1050                                        continue;
1051                                }
1052                                store.baselen = strlen(new_name);
1053                                if (!store_write_section(out_fd, new_name)) {
1054                                        ret = write_error();
1055                                        goto out;
1056                                }
1057                                continue;
1058                        }
1059                        remove = 0;
1060                }
1061                if (remove)
1062                        continue;
1063                length = strlen(buf);
1064                if (write_in_full(out_fd, buf, length) != length) {
1065                        ret = write_error();
1066                        goto out;
1067                }
1068        }
1069        fclose(config_file);
1070 unlock_and_out:
1071        if (close(out_fd) || commit_lock_file(lock) < 0)
1072                        ret = error("Cannot commit config file!");
1073 out:
1074        free(config_filename);
1075        return ret;
1076}