зеркало из https://github.com/microsoft/git.git
Merge branch 'jk/reading-packed-refs'
An earlier rewrite to use strbuf_getwholeline() instead of fgets(3) to read packed-refs file revealed that the former is unacceptably inefficient. * jk/reading-packed-refs: t1430: add another refs-escape test read_packed_refs: avoid double-checking sane refs strbuf_getwholeline: use getdelim if it is available strbuf_getwholeline: avoid calling strbuf_grow strbuf_addch: avoid calling strbuf_grow config: use getc_unlocked when reading from file strbuf_getwholeline: use getc_unlocked git-compat-util: add fallbacks for unlocked stdio strbuf_getwholeline: use getc macro
This commit is contained in:
Коммит
6cc983d0ad
6
Makefile
6
Makefile
|
@ -359,6 +359,8 @@ all::
|
|||
# compiler is detected to support it.
|
||||
#
|
||||
# Define HAVE_BSD_SYSCTL if your platform has a BSD-compatible sysctl function.
|
||||
#
|
||||
# Define HAVE_GETDELIM if your system has the getdelim() function.
|
||||
|
||||
GIT-VERSION-FILE: FORCE
|
||||
@$(SHELL_PATH) ./GIT-VERSION-GEN
|
||||
|
@ -1437,6 +1439,10 @@ ifdef HAVE_BSD_SYSCTL
|
|||
BASIC_CFLAGS += -DHAVE_BSD_SYSCTL
|
||||
endif
|
||||
|
||||
ifdef HAVE_GETDELIM
|
||||
BASIC_CFLAGS += -DHAVE_GETDELIM
|
||||
endif
|
||||
|
||||
ifeq ($(TCLTK_PATH),)
|
||||
NO_TCLTK = NoThanks
|
||||
endif
|
||||
|
|
4
config.c
4
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)
|
||||
|
@ -1088,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;
|
||||
|
|
|
@ -36,6 +36,7 @@ ifeq ($(uname_S),Linux)
|
|||
HAVE_DEV_TTY = YesPlease
|
||||
HAVE_CLOCK_GETTIME = YesPlease
|
||||
HAVE_CLOCK_MONOTONIC = YesPlease
|
||||
HAVE_GETDELIM = YesPlease
|
||||
endif
|
||||
ifeq ($(uname_S),GNU/kFreeBSD)
|
||||
HAVE_ALLOCA_H = YesPlease
|
||||
|
|
|
@ -883,4 +883,10 @@ struct tm *git_gmtime_r(const time_t *, struct tm *);
|
|||
# define SHELL_PATH "/bin/sh"
|
||||
#endif
|
||||
|
||||
#ifndef _POSIX_THREAD_SAFE_FUNCTIONS
|
||||
#define flockfile(fh)
|
||||
#define funlockfile(fh)
|
||||
#define getc_unlocked(fh) getc(fh)
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
6
refs.c
6
refs.c
|
@ -344,8 +344,6 @@ static struct ref_entry *create_ref_entry(const char *refname,
|
|||
if (check_name &&
|
||||
check_refname_format(refname, REFNAME_ALLOW_ONELEVEL))
|
||||
die("Reference has invalid format: '%s'", refname);
|
||||
if (!check_name && !refname_is_safe(refname))
|
||||
die("Reference has invalid name: '%s'", refname);
|
||||
len = strlen(refname) + 1;
|
||||
ref = xmalloc(sizeof(struct ref_entry) + len);
|
||||
hashcpy(ref->u.value.sha1, sha1);
|
||||
|
@ -1178,6 +1176,8 @@ static void read_packed_refs(FILE *f, struct ref_dir *dir)
|
|||
int flag = REF_ISPACKED;
|
||||
|
||||
if (check_refname_format(refname, REFNAME_ALLOW_ONELEVEL)) {
|
||||
if (!refname_is_safe(refname))
|
||||
die("packed refname is dangerous: %s", refname);
|
||||
hashclr(sha1);
|
||||
flag |= REF_BAD_NAME | REF_ISBROKEN;
|
||||
}
|
||||
|
@ -1323,6 +1323,8 @@ static void read_loose_refs(const char *dirname, struct ref_dir *dir)
|
|||
}
|
||||
if (check_refname_format(refname.buf,
|
||||
REFNAME_ALLOW_ONELEVEL)) {
|
||||
if (!refname_is_safe(refname.buf))
|
||||
die("loose refname is dangerous: %s", refname.buf);
|
||||
hashclr(sha1);
|
||||
flag |= REF_BAD_NAME | REF_ISBROKEN;
|
||||
}
|
||||
|
|
47
strbuf.c
47
strbuf.c
|
@ -435,6 +435,47 @@ int strbuf_getcwd(struct strbuf *sb)
|
|||
return -1;
|
||||
}
|
||||
|
||||
#ifdef HAVE_GETDELIM
|
||||
int strbuf_getwholeline(struct strbuf *sb, FILE *fp, int term)
|
||||
{
|
||||
ssize_t r;
|
||||
|
||||
if (feof(fp))
|
||||
return EOF;
|
||||
|
||||
strbuf_reset(sb);
|
||||
|
||||
/* Translate slopbuf to NULL, as we cannot call realloc on it */
|
||||
if (!sb->alloc)
|
||||
sb->buf = NULL;
|
||||
r = getdelim(&sb->buf, &sb->alloc, term, fp);
|
||||
|
||||
if (r > 0) {
|
||||
sb->len = r;
|
||||
return 0;
|
||||
}
|
||||
assert(r == -1);
|
||||
|
||||
/*
|
||||
* Normally we would have called xrealloc, which will try to free
|
||||
* memory and recover. But we have no way to tell getdelim() to do so.
|
||||
* Worse, we cannot try to recover ENOMEM ourselves, because we have
|
||||
* no idea how many bytes were read by getdelim.
|
||||
*
|
||||
* Dying here is reasonable. It mirrors what xrealloc would do on
|
||||
* catastrophic memory failure. We skip the opportunity to free pack
|
||||
* memory and retry, but that's unlikely to help for a malloc small
|
||||
* enough to hold a single line of input, anyway.
|
||||
*/
|
||||
if (errno == ENOMEM)
|
||||
die("Out of memory, getdelim failed");
|
||||
|
||||
/* Restore slopbuf that we moved out of the way before */
|
||||
if (!sb->buf)
|
||||
strbuf_init(sb, 0);
|
||||
return EOF;
|
||||
}
|
||||
#else
|
||||
int strbuf_getwholeline(struct strbuf *sb, FILE *fp, int term)
|
||||
{
|
||||
int ch;
|
||||
|
@ -443,18 +484,22 @@ int strbuf_getwholeline(struct strbuf *sb, FILE *fp, int term)
|
|||
return EOF;
|
||||
|
||||
strbuf_reset(sb);
|
||||
while ((ch = fgetc(fp)) != EOF) {
|
||||
flockfile(fp);
|
||||
while ((ch = getc_unlocked(fp)) != EOF) {
|
||||
if (!strbuf_avail(sb))
|
||||
strbuf_grow(sb, 1);
|
||||
sb->buf[sb->len++] = ch;
|
||||
if (ch == term)
|
||||
break;
|
||||
}
|
||||
funlockfile(fp);
|
||||
if (ch == EOF && sb->len == 0)
|
||||
return EOF;
|
||||
|
||||
sb->buf[sb->len] = '\0';
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
int strbuf_getline(struct strbuf *sb, FILE *fp, int term)
|
||||
{
|
||||
|
|
1
strbuf.h
1
strbuf.h
|
@ -205,6 +205,7 @@ extern int strbuf_cmp(const struct strbuf *, const struct strbuf *);
|
|||
*/
|
||||
static inline void strbuf_addch(struct strbuf *sb, int c)
|
||||
{
|
||||
if (!strbuf_avail(sb))
|
||||
strbuf_grow(sb, 1);
|
||||
sb->buf[sb->len++] = c;
|
||||
sb->buf[sb->len] = '\0';
|
||||
|
|
|
@ -68,6 +68,14 @@ test_expect_success 'branch -D cannot delete non-ref in .git dir' '
|
|||
test_cmp expect .git/my-private-file
|
||||
'
|
||||
|
||||
test_expect_success 'branch -D cannot delete ref in .git dir' '
|
||||
git rev-parse HEAD >.git/my-private-file &&
|
||||
git rev-parse HEAD >expect &&
|
||||
git branch foo/legit &&
|
||||
test_must_fail git branch -D foo////./././../../../my-private-file &&
|
||||
test_cmp expect .git/my-private-file
|
||||
'
|
||||
|
||||
test_expect_success 'branch -D cannot delete absolute path' '
|
||||
git branch -f extra &&
|
||||
test_must_fail git branch -D "$(pwd)/.git/refs/heads/extra" &&
|
||||
|
|
Загрузка…
Ссылка в новой задаче