From: Junio C Hamano Date: Tue, 3 Jun 2014 19:06:46 +0000 (-0700) Subject: Merge branch 'ew/config-protect-mode' X-Git-Tag: v2.1.0-rc0~181 X-Git-Url: https://git.lorimer.id.au/gitweb.git/diff_plain/a3c0efec9b35a7db41537cc9f80e3ebb7ce2fbfe?ds=inline;hp=-c Merge branch 'ew/config-protect-mode' * ew/config-protect-mode: config: preserve config file permissions on edits --- a3c0efec9b35a7db41537cc9f80e3ebb7ce2fbfe diff --combined config.c index a30cb5c07d,62de69e148..c227aa8517 --- a/config.c +++ b/config.c @@@ -21,7 -21,6 +21,7 @@@ struct config_source } buf; } u; const char *name; + const char *path; int die_on_error; int linenr; int eof; @@@ -102,12 -101,12 +102,12 @@@ static int handle_path_include(const ch if (!is_absolute_path(path)) { char *slash; - if (!cf || !cf->name) + if (!cf || !cf->path) return error("relative config includes must come from files"); - slash = find_last_dir_sep(cf->name); + slash = find_last_dir_sep(cf->path); if (slash) - strbuf_add(&buf, cf->name, slash - cf->name + 1); + strbuf_add(&buf, cf->path, slash - cf->path + 1); strbuf_addstr(&buf, path); path = buf.buf; } @@@ -557,7 -556,6 +557,7 @@@ int git_parse_ulong(const char *value, return 1; } +NORETURN static void die_bad_number(const char *name, const char *value) { const char *reason = errno == ERANGE ? @@@ -669,7 -667,20 +669,7 @@@ static int git_default_core_config(cons trust_ctime = git_config_bool(var, value); return 0; } - if (!strcmp(var, "core.statinfo") || - !strcmp(var, "core.checkstat")) { - /* - * NEEDSWORK: statinfo was a typo in v1.8.2 that has - * never been advertised. we will remove it at Git - * 2.0 boundary. - */ - if (!strcmp(var, "core.statinfo")) { - static int warned; - if (!warned++) { - warning("'core.statinfo' will be removed in Git 2.0; " - "use 'core.checkstat' instead."); - } - } + if (!strcmp(var, "core.checkstat")) { if (!strcasecmp(value, "default")) check_stat = 1; else if (!strcasecmp(value, "minimal")) @@@ -1023,35 -1034,24 +1023,35 @@@ static int do_config_from(struct config return ret; } -int git_config_from_file(config_fn_t fn, const char *filename, void *data) +static int do_config_from_file(config_fn_t fn, + const char *name, const char *path, FILE *f, void *data) { - int ret; - FILE *f = fopen(filename, "r"); + struct config_source top; - ret = -1; - if (f) { - struct config_source top; + top.u.file = f; + top.name = name; + top.path = path; + top.die_on_error = 1; + top.do_fgetc = config_file_fgetc; + top.do_ungetc = config_file_ungetc; + top.do_ftell = config_file_ftell; - top.u.file = f; - top.name = filename; - top.die_on_error = 1; - top.do_fgetc = config_file_fgetc; - top.do_ungetc = config_file_ungetc; - top.do_ftell = config_file_ftell; + return do_config_from(&top, fn, data); +} + +static int git_config_from_stdin(config_fn_t fn, void *data) +{ + return do_config_from_file(fn, "", NULL, stdin, data); +} - ret = do_config_from(&top, fn, data); +int git_config_from_file(config_fn_t fn, const char *filename, void *data) +{ + int ret = -1; + FILE *f; + f = fopen(filename, "r"); + if (f) { + ret = do_config_from_file(fn, filename, filename, f, data); fclose(f); } return ret; @@@ -1066,7 -1066,6 +1066,7 @@@ int git_config_from_buf(config_fn_t fn top.u.buf.len = len; top.u.buf.pos = 0; top.name = name; + top.path = NULL; top.die_on_error = 0; top.do_fgetc = config_buf_fgetc; top.do_ungetc = config_buf_ungetc; @@@ -1175,7 -1174,8 +1175,7 @@@ int git_config_early(config_fn_t fn, vo } int git_config_with_options(config_fn_t fn, void *data, - const char *filename, - const char *blob_ref, + struct git_config_source *config_source, int respect_includes) { char *repo_config = NULL; @@@ -1193,12 -1193,10 +1193,12 @@@ * If we have a specific filename, use it. Otherwise, follow the * regular lookup sequence. */ - if (filename) - return git_config_from_file(fn, filename, data); - else if (blob_ref) - return git_config_from_blob_ref(fn, blob_ref, data); + if (config_source && config_source->use_stdin) + return git_config_from_stdin(fn, data); + else if (config_source && config_source->file) + return git_config_from_file(fn, config_source->file, data); + else if (config_source && config_source->blob) + return git_config_from_blob_ref(fn, config_source->blob, data); repo_config = git_pathdup("config"); ret = git_config_early(fn, data, repo_config); @@@ -1209,7 -1207,7 +1209,7 @@@ int git_config(config_fn_t fn, void *data) { - return git_config_with_options(fn, data, NULL, NULL, 1); + return git_config_with_options(fn, data, NULL, 1); } /* @@@ -1636,6 -1634,13 +1636,13 @@@ int git_config_set_multivar_in_file(con MAP_PRIVATE, in_fd, 0); close(in_fd); + if (fchmod(fd, st.st_mode & 07777) < 0) { + error("fchmod on %s failed: %s", + lock->filename, strerror(errno)); + ret = CONFIG_NO_WRITE; + goto out_free; + } + if (store.seen == 0) store.seen = 1; @@@ -1784,6 -1789,7 +1791,7 @@@ int git_config_rename_section_in_file(c int out_fd; char buf[1024]; FILE *config_file; + struct stat st; if (new_name && !section_name_is_ok(new_name)) { ret = error("invalid section name: %s", new_name); @@@ -1805,6 -1811,14 +1813,14 @@@ goto unlock_and_out; } + fstat(fileno(config_file), &st); + + if (fchmod(out_fd, st.st_mode & 07777) < 0) { + ret = error("fchmod on %s failed: %s", + lock->filename, strerror(errno)); + goto out; + } + while (fgets(buf, sizeof(buf), config_file)) { int i; int length; diff --combined t/t1300-repo-config.sh index 58cd5435be,ba41bc93ee..3f80ff0c14 --- a/t/t1300-repo-config.sh +++ b/t/t1300-repo-config.sh @@@ -461,7 -461,7 +461,7 @@@ test_expect_success 'new variable inser test_cmp expect .git/config ' -test_expect_success 'alternative GIT_CONFIG (non-existing file should fail)' ' +test_expect_success 'alternative --file (non-existing file should fail)' ' test_must_fail git config --file non-existing-config -l ' @@@ -475,28 -475,15 +475,28 @@@ ein.bahn=strass EOF test_expect_success 'alternative GIT_CONFIG' ' - GIT_CONFIG=other-config git config -l >output && + GIT_CONFIG=other-config git config --list >output && test_cmp expect output ' test_expect_success 'alternative GIT_CONFIG (--file)' ' - git config --file other-config -l > output && + git config --file other-config --list >output && test_cmp expect output ' +test_expect_success 'alternative GIT_CONFIG (--file=-)' ' + git config --file - --list output && + test_cmp expect output +' + +test_expect_success 'setting a value in stdin is an error' ' + test_must_fail git config --file - some.value foo +' + +test_expect_success 'editing stdin is an error' ' + test_must_fail git config --file - --edit +' + test_expect_success 'refer config from subdirectory' ' mkdir x && ( @@@ -508,10 -495,10 +508,10 @@@ ' -test_expect_success 'refer config from subdirectory via GIT_CONFIG' ' +test_expect_success 'refer config from subdirectory via --file' ' ( cd x && - GIT_CONFIG=../other-config git config --get ein.bahn >actual && + git config --file=../other-config --get ein.bahn >actual && test_cmp expect actual ) ' @@@ -523,8 -510,8 +523,8 @@@ cat > expect << EO park = ausweis EOF -test_expect_success '--set in alternative GIT_CONFIG' ' - GIT_CONFIG=other-config git config anwohner.park ausweis && +test_expect_success '--set in alternative file' ' + git config --file=other-config anwohner.park ausweis && test_cmp expect other-config ' @@@ -955,11 -942,11 +955,11 @@@ test_expect_success 'inner whitespace k test_expect_success SYMLINKS 'symlinked configuration' ' ln -s notyet myconfig && - GIT_CONFIG=myconfig git config test.frotz nitfol && + git config --file=myconfig test.frotz nitfol && test -h myconfig && test -f notyet && - test "z$(GIT_CONFIG=notyet git config test.frotz)" = znitfol && - GIT_CONFIG=myconfig git config test.xyzzy rezrov && + test "z$(git config --file=notyet test.frotz)" = znitfol && + git config --file=myconfig test.xyzzy rezrov && test -h myconfig && test -f notyet && cat >expect <<-\EOF && @@@ -967,22 -954,31 +967,22 @@@ rezrov EOF { - GIT_CONFIG=notyet git config test.frotz && - GIT_CONFIG=notyet git config test.xyzzy + git config --file=notyet test.frotz && + git config --file=notyet test.xyzzy } >actual && test_cmp expect actual ' test_expect_success 'nonexistent configuration' ' - ( - GIT_CONFIG=doesnotexist && - export GIT_CONFIG && - test_must_fail git config --list && - test_must_fail git config test.xyzzy - ) + test_must_fail git config --file=doesnotexist --list && + test_must_fail git config --file=doesnotexist test.xyzzy ' test_expect_success SYMLINKS 'symlink to nonexistent configuration' ' ln -s doesnotexist linktonada && ln -s linktonada linktolinktonada && - ( - GIT_CONFIG=linktonada && - export GIT_CONFIG && - test_must_fail git config --list && - GIT_CONFIG=linktolinktonada && - test_must_fail git config --list - ) + test_must_fail git config --file=linktonada --list && + test_must_fail git config --file=linktolinktonada --list ' test_expect_success 'check split_cmdline return' " @@@ -1158,4 -1154,14 +1158,14 @@@ test_expect_failure 'adding a key into test_cmp expect .git/config ' + test_expect_success POSIXPERM,PERL 'preserves existing permissions' ' + chmod 0600 .git/config && + git config imap.pass Hunter2 && + perl -e \ + "die q(badset) if ((stat(q(.git/config)))[2] & 07777) != 0600" && + git config --rename-section imap pop && + perl -e \ + "die q(badrename) if ((stat(q(.git/config)))[2] & 07777) != 0600" + ' + test_done