Sync with 2.31.8

* maint-2.31: (25 commits)
  Git 2.31.8
  tests: avoid using `test_i18ncmp`
  Git 2.30.9
  gettext: avoid using gettext if the locale dir is not present
  apply --reject: overwrite existing `.rej` symlink if it exists
  http.c: clear the 'finished' member once we are done with it
  clone.c: avoid "exceeds maximum object size" error with GCC v12.x
  range-diff: use ssize_t for parsed "len" in read_patches()
  range-diff: handle unterminated lines in read_patches()
  range-diff: drop useless "offset" variable from read_patches()
  t5604: GETTEXT_POISON fix, conclusion
  t5604: GETTEXT_POISON fix, part 1
  t5619: GETTEXT_POISON fix
  t0003: GETTEXT_POISON fix, conclusion
  t0003: GETTEXT_POISON fix, part 1
  t0033: GETTEXT_POISON fix
  http: support CURLOPT_PROTOCOLS_STR
  http: prefer CURLOPT_SEEKFUNCTION to CURLOPT_IOCTLFUNCTION
  http-push: prefer CURLOPT_UPLOAD to CURLOPT_PUT
  ci: install python on ubuntu
  ci: use the same version of p4 on both Linux and macOS
  ...
This commit is contained in:
Johannes Schindelin 2023-03-11 19:24:34 +01:00
commit 31f7fe5e34
21 changed files with 291 additions and 98 deletions

View File

@ -287,7 +287,7 @@ jobs:
pool: ubuntu-latest
- jobname: linux-gcc
cc: gcc
pool: ubuntu-latest
pool: ubuntu-20.04
- jobname: osx-clang
cc: clang
pool: macos-latest
@ -345,7 +345,7 @@ jobs:
if: needs.ci-config.outputs.enabled == 'yes'
env:
jobname: StaticAnalysis
runs-on: ubuntu-18.04
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v1
- run: ci/install-dependencies.sh

View File

@ -0,0 +1,43 @@
Git v2.30.9 Release Notes
=========================
This release addresses the security issues CVE-2023-25652,
CVE-2023-25815, and CVE-2023-29007.
Fixes since v2.30.8
-------------------
* CVE-2023-25652:
By feeding specially crafted input to `git apply --reject`, a
path outside the working tree can be overwritten with partially
controlled contents (corresponding to the rejected hunk(s) from
the given patch).
* CVE-2023-25815:
When Git is compiled with runtime prefix support and runs without
translated messages, it still used the gettext machinery to
display messages, which subsequently potentially looked for
translated messages in unexpected places. This allowed for
malicious placement of crafted messages.
* CVE-2023-29007:
When renaming or deleting a section from a configuration file,
certain malicious configuration values may be misinterpreted as
the beginning of a new configuration section, leading to arbitrary
configuration injection.
Credit for finding CVE-2023-25652 goes to Ry0taK, and the fix was
developed by Taylor Blau, Junio C Hamano and Johannes Schindelin,
with the help of Linus Torvalds.
Credit for finding CVE-2023-25815 goes to Maxime Escourbiac and
Yassine BENGANA of Michelin, and the fix was developed by Johannes
Schindelin.
Credit for finding CVE-2023-29007 goes to André Baptista and Vítor Pinho
of Ethiack, and the fix was developed by Taylor Blau, and Johannes
Schindelin, with help from Jeff King, and Patrick Steinhardt.

View File

@ -0,0 +1,6 @@
Git v2.31.8 Release Notes
=========================
This release merges the fixes that appear in v2.30.9 to address the
security issues CVE-2023-25652, CVE-2023-25815, and CVE-2023-29007;
see the release notes for that version for details.

View File

@ -145,6 +145,10 @@ Issues of note:
patches into an IMAP mailbox, you do not have to have them
(use NO_CURL).
Git requires version "7.19.5" or later of "libcurl" to build
without NO_CURL. This version requirement may be bumped in
the future.
- "expat" library; git-http-push uses it for remote lock
management over DAV. Similar to "curl" above, this is optional
(with NO_EXPAT).

14
apply.c
View File

@ -4560,7 +4560,7 @@ static int write_out_one_reject(struct apply_state *state, struct patch *patch)
FILE *rej;
char namebuf[PATH_MAX];
struct fragment *frag;
int cnt = 0;
int fd, cnt = 0;
struct strbuf sb = STRBUF_INIT;
for (cnt = 0, frag = patch->fragments; frag; frag = frag->next) {
@ -4600,7 +4600,17 @@ static int write_out_one_reject(struct apply_state *state, struct patch *patch)
memcpy(namebuf, patch->new_name, cnt);
memcpy(namebuf + cnt, ".rej", 5);
rej = fopen(namebuf, "w");
fd = open(namebuf, O_CREAT | O_EXCL | O_WRONLY, 0666);
if (fd < 0) {
if (errno != EEXIST)
return error_errno(_("cannot open %s"), namebuf);
if (unlink(namebuf))
return error_errno(_("cannot unlink '%s'"), namebuf);
fd = open(namebuf, O_CREAT | O_EXCL | O_WRONLY, 0666);
if (fd < 0)
return error_errno(_("cannot open %s"), namebuf);
}
rej = fdopen(fd, "w");
if (!rej)
return error_errno(_("cannot open %s"), namebuf);

View File

@ -254,6 +254,15 @@ static char *guess_dir_name(const char *repo, int is_bundle, int is_bare)
end--;
}
/*
* It should not be possible to overflow `ptrdiff_t` by passing in an
* insanely long URL, but GCC does not know that and will complain
* without this check.
*/
if (end - start < 0)
die(_("No directory name could be guessed.\n"
"Please specify a directory on the command line"));
/*
* Strip trailing port number if we've got only a
* hostname (that is, there is no dir separator but a

View File

@ -5,7 +5,7 @@
. ${0%/*}/lib.sh
P4WHENCE=http://filehost.perforce.com/perforce/r$LINUX_P4_VERSION
P4WHENCE=https://cdist2.perforce.com/perforce/r21.2
LFSWHENCE=https://github.com/github/git-lfs/releases/download/v$LINUX_GIT_LFS_VERSION
UBUNTU_COMMON_PKGS="make libssl-dev libcurl4-openssl-dev libexpat-dev
tcl tk gettext zlib1g-dev perl-modules liberror-perl libauthen-sasl-perl
@ -16,7 +16,7 @@ linux-clang|linux-gcc)
sudo apt-add-repository -y "ppa:ubuntu-toolchain-r/test"
sudo apt-get -q update
sudo apt-get -q -y install language-pack-is libsvn-perl apache2 \
$UBUNTU_COMMON_PKGS
$UBUNTU_COMMON_PKGS $PYTHON_PACKAGE
case "$jobname" in
linux-gcc)
sudo apt-get -q -y install gcc-8
@ -44,13 +44,15 @@ osx-clang|osx-gcc)
test -z "$BREW_INSTALL_PACKAGES" ||
brew install $BREW_INSTALL_PACKAGES
brew link --force gettext
brew install --cask --no-quarantine perforce || {
# Update the definitions and try again
cask_repo="$(brew --repository)"/Library/Taps/homebrew/homebrew-cask &&
git -C "$cask_repo" pull --no-stat --ff-only &&
brew install --cask --no-quarantine perforce
} ||
brew install homebrew/cask/perforce
mkdir -p $HOME/bin
(
cd $HOME/bin
wget -q "$P4WHENCE/bin.macosx1015x86_64/helix-core-server.tgz" &&
tar -xf helix-core-server.tgz &&
sudo xattr -d com.apple.quarantine p4 p4d 2>/dev/null || true
)
PATH="$PATH:${HOME}/bin"
export PATH
case "$jobname" in
osx-gcc)
brew install gcc@9
@ -81,9 +83,9 @@ esac
if type p4d >/dev/null && type p4 >/dev/null
then
echo "$(tput setaf 6)Perforce Server Version$(tput sgr0)"
p4d -V | grep Rev.
p4d -V
echo "$(tput setaf 6)Perforce Client Version$(tput sgr0)"
p4 -V | grep Rev.
p4 -V
fi
if type git-lfs >/dev/null
then

View File

@ -184,13 +184,13 @@ export SKIP_DASHED_BUILT_INS=YesPlease
case "$jobname" in
linux-clang|linux-gcc)
PYTHON_PACKAGE=python2
if [ "$jobname" = linux-gcc ]
then
export CC=gcc-8
MAKEFLAGS="$MAKEFLAGS PYTHON_PATH=/usr/bin/python3"
else
MAKEFLAGS="$MAKEFLAGS PYTHON_PATH=/usr/bin/python2"
PYTHON_PACKAGE=python3
fi
MAKEFLAGS="$MAKEFLAGS PYTHON_PATH=/usr/bin/$PYTHON_PACKAGE"
export GIT_TEST_HTTPD=true
@ -199,7 +199,6 @@ linux-clang|linux-gcc)
# were recorded in the Homebrew database upon creating the OS X
# image.
# Keep that in mind when you encounter a broken OS X build!
export LINUX_P4_VERSION="16.2"
export LINUX_GIT_LFS_VERSION="1.5.2"
P4_PATH="$HOME/custom/p4"

View File

@ -323,7 +323,6 @@ static NOINLINE void RemoveCacheEntries(nedpool *p, threadcache *tc, unsigned in
}
static void DestroyCaches(nedpool *p) THROWSPEC
{
if(p->caches)
{
threadcache *tc;
int n;

View File

@ -43,6 +43,7 @@ void syslog(int priority, const char *fmt, ...)
va_end(ap);
while ((pos = strstr(str, "%1")) != NULL) {
size_t offset = pos - str;
char *oldstr = str;
str = realloc(str, st_add(++str_len, 1));
if (!str) {
@ -50,6 +51,7 @@ void syslog(int priority, const char *fmt, ...)
warning_errno("realloc failed");
return;
}
pos = str + offset;
memmove(pos + 2, pos + 1, strlen(pos));
pos[1] = ' ';
}

View File

@ -3198,9 +3198,10 @@ void git_config_set_multivar(const char *key, const char *value,
flags);
}
static int section_name_match (const char *buf, const char *name)
static size_t section_name_match (const char *buf, const char *name)
{
int i = 0, j = 0, dot = 0;
size_t i = 0, j = 0;
int dot = 0;
if (buf[i] != '[')
return 0;
for (i = 1; buf[i] && buf[i] != ']'; i++) {
@ -3253,6 +3254,8 @@ static int section_name_is_ok(const char *name)
return 1;
}
#define GIT_CONFIG_MAX_LINE_LEN (512 * 1024)
/* if new_name == NULL, the section is removed instead */
static int git_config_copy_or_rename_section_in_file(const char *config_filename,
const char *old_name,
@ -3262,11 +3265,12 @@ static int git_config_copy_or_rename_section_in_file(const char *config_filename
char *filename_buf = NULL;
struct lock_file lock = LOCK_INIT;
int out_fd;
char buf[1024];
struct strbuf buf = STRBUF_INIT;
FILE *config_file = NULL;
struct stat st;
struct strbuf copystr = STRBUF_INIT;
struct config_store_data store;
uint32_t line_nr = 0;
memset(&store, 0, sizeof(store));
@ -3303,16 +3307,25 @@ static int git_config_copy_or_rename_section_in_file(const char *config_filename
goto out;
}
while (fgets(buf, sizeof(buf), config_file)) {
unsigned i;
int length;
while (!strbuf_getwholeline(&buf, config_file, '\n')) {
size_t i, length;
int is_section = 0;
char *output = buf;
for (i = 0; buf[i] && isspace(buf[i]); i++)
char *output = buf.buf;
line_nr++;
if (buf.len >= GIT_CONFIG_MAX_LINE_LEN) {
ret = error(_("refusing to work with overly long line "
"in '%s' on line %"PRIuMAX),
config_filename, (uintmax_t)line_nr);
goto out;
}
for (i = 0; buf.buf[i] && isspace(buf.buf[i]); i++)
; /* do nothing */
if (buf[i] == '[') {
if (buf.buf[i] == '[') {
/* it's a section */
int offset;
size_t offset;
is_section = 1;
/*
@ -3329,7 +3342,7 @@ static int git_config_copy_or_rename_section_in_file(const char *config_filename
strbuf_reset(&copystr);
}
offset = section_name_match(&buf[i], old_name);
offset = section_name_match(&buf.buf[i], old_name);
if (offset > 0) {
ret++;
if (new_name == NULL) {
@ -3404,6 +3417,7 @@ out:
out_no_rollback:
free(filename_buf);
config_store_data_clear(&store);
strbuf_release(&buf);
return ret;
}

View File

@ -101,6 +101,8 @@ static void init_gettext_charset(const char *domain)
setlocale(LC_CTYPE, "C");
}
int git_gettext_enabled = 0;
void git_setup_gettext(void)
{
const char *podir = getenv(GIT_TEXT_DOMAIN_DIR_ENVIRONMENT);
@ -120,6 +122,8 @@ void git_setup_gettext(void)
init_gettext_charset("git");
textdomain("git");
git_gettext_enabled = 1;
free(p);
}

View File

@ -29,9 +29,11 @@
#define FORMAT_PRESERVING(n) __attribute__((format_arg(n)))
#ifndef NO_GETTEXT
extern int git_gettext_enabled;
void git_setup_gettext(void);
int gettext_width(const char *s);
#else
#define git_gettext_enabled (0)
static inline void git_setup_gettext(void)
{
}
@ -45,12 +47,16 @@ static inline FORMAT_PRESERVING(1) const char *_(const char *msgid)
{
if (!*msgid)
return "";
if (!git_gettext_enabled)
return msgid;
return gettext(msgid);
}
static inline FORMAT_PRESERVING(1) FORMAT_PRESERVING(2)
const char *Q_(const char *msgid, const char *plu, unsigned long n)
{
if (!git_gettext_enabled)
return n == 1 ? msgid : plu;
return ngettext(msgid, plu, n);
}

View File

@ -198,14 +198,14 @@ static void curl_setup_http(CURL *curl, const char *url,
const char *custom_req, struct buffer *buffer,
curl_write_callback write_fn)
{
curl_easy_setopt(curl, CURLOPT_PUT, 1);
curl_easy_setopt(curl, CURLOPT_UPLOAD, 1);
curl_easy_setopt(curl, CURLOPT_URL, url);
curl_easy_setopt(curl, CURLOPT_INFILE, buffer);
curl_easy_setopt(curl, CURLOPT_INFILESIZE, buffer->buf.len);
curl_easy_setopt(curl, CURLOPT_READFUNCTION, fread_buffer);
#ifndef NO_CURL_IOCTL
curl_easy_setopt(curl, CURLOPT_IOCTLFUNCTION, ioctl_buffer);
curl_easy_setopt(curl, CURLOPT_IOCTLDATA, buffer);
#ifndef NO_CURL_SEEK
curl_easy_setopt(curl, CURLOPT_SEEKFUNCTION, seek_buffer);
curl_easy_setopt(curl, CURLOPT_SEEKDATA, buffer);
#endif
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_fn);
curl_easy_setopt(curl, CURLOPT_NOBODY, 0);

105
http.c
View File

@ -186,22 +186,20 @@ size_t fread_buffer(char *ptr, size_t eltsize, size_t nmemb, void *buffer_)
return size / eltsize;
}
#ifndef NO_CURL_IOCTL
curlioerr ioctl_buffer(CURL *handle, int cmd, void *clientp)
#ifndef NO_CURL_SEEK
int seek_buffer(void *clientp, curl_off_t offset, int origin)
{
struct buffer *buffer = clientp;
switch (cmd) {
case CURLIOCMD_NOP:
return CURLIOE_OK;
case CURLIOCMD_RESTARTREAD:
buffer->posn = 0;
return CURLIOE_OK;
default:
return CURLIOE_UNKNOWNCMD;
if (origin != SEEK_SET)
BUG("seek_buffer only handles SEEK_SET");
if (offset < 0 || offset >= buffer->buf.len) {
error("curl seek would be outside of buffer");
return CURL_SEEKFUNC_FAIL;
}
buffer->posn = offset;
return CURL_SEEKFUNC_OK;
}
#endif
@ -810,20 +808,37 @@ void setup_curl_trace(CURL *handle)
}
#ifdef CURLPROTO_HTTP
static long get_curl_allowed_protocols(int from_user)
static void proto_list_append(struct strbuf *list, const char *proto)
{
long allowed_protocols = 0;
if (!list)
return;
if (list->len)
strbuf_addch(list, ',');
strbuf_addstr(list, proto);
}
if (is_transport_allowed("http", from_user))
allowed_protocols |= CURLPROTO_HTTP;
if (is_transport_allowed("https", from_user))
allowed_protocols |= CURLPROTO_HTTPS;
if (is_transport_allowed("ftp", from_user))
allowed_protocols |= CURLPROTO_FTP;
if (is_transport_allowed("ftps", from_user))
allowed_protocols |= CURLPROTO_FTPS;
static long get_curl_allowed_protocols(int from_user, struct strbuf *list)
{
long bits = 0;
return allowed_protocols;
if (is_transport_allowed("http", from_user)) {
bits |= CURLPROTO_HTTP;
proto_list_append(list, "http");
}
if (is_transport_allowed("https", from_user)) {
bits |= CURLPROTO_HTTPS;
proto_list_append(list, "https");
}
if (is_transport_allowed("ftp", from_user)) {
bits |= CURLPROTO_FTP;
proto_list_append(list, "ftp");
}
if (is_transport_allowed("ftps", from_user)) {
bits |= CURLPROTO_FTPS;
proto_list_append(list, "ftps");
}
return bits;
}
#endif
@ -981,10 +996,24 @@ static CURL *get_curl_handle(void)
curl_easy_setopt(result, CURLOPT_POST301, 1);
#endif
#ifdef CURLPROTO_HTTP
#if LIBCURL_VERSION_NUM >= 0x075500
{
struct strbuf buf = STRBUF_INIT;
get_curl_allowed_protocols(0, &buf);
curl_easy_setopt(result, CURLOPT_REDIR_PROTOCOLS_STR, buf.buf);
strbuf_reset(&buf);
get_curl_allowed_protocols(-1, &buf);
curl_easy_setopt(result, CURLOPT_PROTOCOLS_STR, buf.buf);
strbuf_release(&buf);
}
#else
curl_easy_setopt(result, CURLOPT_REDIR_PROTOCOLS,
get_curl_allowed_protocols(0));
get_curl_allowed_protocols(0, NULL));
curl_easy_setopt(result, CURLOPT_PROTOCOLS,
get_curl_allowed_protocols(-1));
get_curl_allowed_protocols(-1, NULL));
#endif
#else
warning(_("Protocol restrictions not supported with cURL < 7.19.4"));
#endif
@ -1523,6 +1552,32 @@ void run_active_slot(struct active_request_slot *slot)
finish_active_slot(slot);
}
#endif
/*
* The value of slot->finished we set before the loop was used
* to set our "finished" variable when our request completed.
*
* 1. The slot may not have been reused for another requst
* yet, in which case it still has &finished.
*
* 2. The slot may already be in-use to serve another request,
* which can further be divided into two cases:
*
* (a) If call run_active_slot() hasn't been called for that
* other request, slot->finished would have been cleared
* by get_active_slot() and has NULL.
*
* (b) If the request did call run_active_slot(), then the
* call would have updated slot->finished at the beginning
* of this function, and with the clearing of the member
* below, we would find that slot->finished is now NULL.
*
* In all cases, slot->finished has no useful information to
* anybody at this point. Some compilers warn us for
* attempting to smuggle a pointer that is about to become
* invalid, i.e. &finished. We clear it here to assure them.
*/
slot->finished = NULL;
}
static void release_active_slot(struct active_request_slot *slot)

8
http.h
View File

@ -41,8 +41,8 @@
#define CURLE_HTTP_RETURNED_ERROR CURLE_HTTP_NOT_FOUND
#endif
#if LIBCURL_VERSION_NUM < 0x070c03
#define NO_CURL_IOCTL
#if LIBCURL_VERSION_NUM < 0x071200
#define NO_CURL_SEEK
#endif
/*
@ -82,8 +82,8 @@ struct buffer {
size_t fread_buffer(char *ptr, size_t eltsize, size_t nmemb, void *strbuf);
size_t fwrite_buffer(char *ptr, size_t eltsize, size_t nmemb, void *strbuf);
size_t fwrite_null(char *ptr, size_t eltsize, size_t nmemb, void *strbuf);
#ifndef NO_CURL_IOCTL
curlioerr ioctl_buffer(CURL *handle, int cmd, void *clientp);
#ifndef NO_CURL_SEEK
int seek_buffer(void *clientp, curl_off_t offset, int origin);
#endif
/* Slot lifecycle functions */

View File

@ -26,17 +26,6 @@ struct patch_util {
struct object_id oid;
};
static size_t find_end_of_line(char *buffer, unsigned long size)
{
char *eol = memchr(buffer, '\n', size);
if (!eol)
return size;
*eol = '\0';
return eol + 1 - buffer;
}
/*
* Reads the patches into a string list, with the `util` field being populated
* as struct object_id (will need to be free()d).
@ -49,7 +38,7 @@ static int read_patches(const char *range, struct string_list *list,
struct patch_util *util = NULL;
int in_header = 1;
char *line, *current_filename = NULL;
int offset, len;
ssize_t len;
size_t size;
strvec_pushl(&cp.args, "log", "--no-color", "-p", "--no-merges",
@ -86,11 +75,18 @@ static int read_patches(const char *range, struct string_list *list,
line = contents.buf;
size = contents.len;
for (offset = 0; size > 0; offset += len, size -= len, line += len) {
for (; size > 0; size -= len, line += len) {
const char *p;
char *eol;
eol = memchr(line, '\n', size);
if (eol) {
*eol = '\0';
len = eol + 1 - line;
} else {
len = size;
}
len = find_end_of_line(line, size);
line[len - 1] = '\0';
if (skip_prefix(line, "commit ", &p)) {
if (util) {
string_list_append(list, buf.buf)->util = util;
@ -132,7 +128,8 @@ static int read_patches(const char *range, struct string_list *list,
strbuf_addch(&buf, '\n');
if (!util->diff_offset)
util->diff_offset = buf.len;
line[len - 1] = '\n';
if (eol)
*eol = '\n';
orig_len = len;
len = parse_git_diff_header(&root, &linenr, 0, line,
len, size, &patch);

View File

@ -709,26 +709,24 @@ static size_t rpc_out(void *ptr, size_t eltsize,
return avail;
}
#ifndef NO_CURL_IOCTL
static curlioerr rpc_ioctl(CURL *handle, int cmd, void *clientp)
#ifndef NO_CURL_SEEK
static int rpc_seek(void *clientp, curl_off_t offset, int origin)
{
struct rpc_state *rpc = clientp;
switch (cmd) {
case CURLIOCMD_NOP:
return CURLIOE_OK;
if (origin != SEEK_SET)
BUG("rpc_seek only handles SEEK_SET, not %d", origin);
case CURLIOCMD_RESTARTREAD:
if (rpc->initial_buffer) {
rpc->pos = 0;
return CURLIOE_OK;
if (rpc->initial_buffer) {
if (offset < 0 || offset > rpc->len) {
error("curl seek would be outside of rpc buffer");
return CURL_SEEKFUNC_FAIL;
}
error(_("unable to rewind rpc post data - try increasing http.postBuffer"));
return CURLIOE_FAILRESTART;
default:
return CURLIOE_UNKNOWNCMD;
rpc->pos = offset;
return CURL_SEEKFUNC_OK;
}
error(_("unable to rewind rpc post data - try increasing http.postBuffer"));
return CURL_SEEKFUNC_FAIL;
}
#endif
@ -949,9 +947,9 @@ retry:
rpc->initial_buffer = 1;
curl_easy_setopt(slot->curl, CURLOPT_READFUNCTION, rpc_out);
curl_easy_setopt(slot->curl, CURLOPT_INFILE, rpc);
#ifndef NO_CURL_IOCTL
curl_easy_setopt(slot->curl, CURLOPT_IOCTLFUNCTION, rpc_ioctl);
curl_easy_setopt(slot->curl, CURLOPT_IOCTLDATA, rpc);
#ifndef NO_CURL_SEEK
curl_easy_setopt(slot->curl, CURLOPT_SEEKFUNCTION, rpc_seek);
curl_easy_setopt(slot->curl, CURLOPT_SEEKDATA, rpc);
#endif
if (options.verbosity > 1) {
fprintf(stderr, "POST %s (chunked)\n", rpc->service_name);

View File

@ -9,7 +9,7 @@ export GIT_TEST_ASSUME_DIFFERENT_OWNER
expect_rejected_dir () {
test_must_fail git status 2>err &&
grep "safe.directory" err
grep "dubious ownership" err
}
test_expect_success 'safe.directory is not set' '

View File

@ -616,6 +616,36 @@ test_expect_success 'renaming to bogus section is rejected' '
test_must_fail git config --rename-section branch.zwei "bogus name"
'
test_expect_success 'renaming a section with a long line' '
{
printf "[b]\\n" &&
printf " c = d %1024s [a] e = f\\n" " " &&
printf "[a] g = h\\n"
} >y &&
git config -f y --rename-section a xyz &&
test_must_fail git config -f y b.e
'
test_expect_success 'renaming an embedded section with a long line' '
{
printf "[b]\\n" &&
printf " c = d %1024s [a] [foo] e = f\\n" " " &&
printf "[a] g = h\\n"
} >y &&
git config -f y --rename-section a xyz &&
test_must_fail git config -f y foo.e
'
test_expect_success 'renaming a section with an overly-long line' '
{
printf "[b]\\n" &&
printf " c = d %525000s e" " " &&
printf "[a] g = h\\n"
} >y &&
test_must_fail git config -f y --rename-section a xyz 2>err &&
grep "refusing to work with overly long line in .y. on line 2" err
'
cat >> .git/config << EOF
[branch "zwei"] a = 1 [branch "vier"]
EOF

View File

@ -125,4 +125,19 @@ test_expect_success SYMLINKS 'symlink escape when deleting file' '
test_path_is_file .git/delete-me
'
test_expect_success SYMLINKS '--reject removes .rej symlink if it exists' '
test_when_finished "git reset --hard && git clean -dfx" &&
test_commit file &&
echo modified >file.t &&
git diff -- file.t >patch &&
echo modified-again >file.t &&
ln -s foo file.t.rej &&
test_must_fail git apply patch --reject 2>err &&
test_i18ngrep "Rejected hunk" err &&
test_path_is_missing foo &&
test_path_is_file file.t.rej
'
test_done