зеркало из https://github.com/microsoft/git.git
Merge branch 'rs/apply-validate-input' into maint
Tighten error checks for invalid "git apply" input. * rs/apply-validate-input: apply: check git diffs for mutually exclusive header lines apply: check git diffs for invalid file modes apply: check git diffs for missing old filenames
This commit is contained in:
Коммит
33c3c2d368
35
apply.c
35
apply.c
|
@ -210,6 +210,7 @@ struct patch {
|
|||
unsigned ws_rule;
|
||||
int lines_added, lines_deleted;
|
||||
int score;
|
||||
int extension_linenr; /* first line specifying delete/new/rename/copy */
|
||||
unsigned int is_toplevel_relative:1;
|
||||
unsigned int inaccurate_eof:1;
|
||||
unsigned int is_binary:1;
|
||||
|
@ -1011,20 +1012,27 @@ static int gitdiff_newname(struct apply_state *state,
|
|||
DIFF_NEW_NAME);
|
||||
}
|
||||
|
||||
static int parse_mode_line(const char *line, int linenr, unsigned int *mode)
|
||||
{
|
||||
char *end;
|
||||
*mode = strtoul(line, &end, 8);
|
||||
if (end == line || !isspace(*end))
|
||||
return error(_("invalid mode on line %d: %s"), linenr, line);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int gitdiff_oldmode(struct apply_state *state,
|
||||
const char *line,
|
||||
struct patch *patch)
|
||||
{
|
||||
patch->old_mode = strtoul(line, NULL, 8);
|
||||
return 0;
|
||||
return parse_mode_line(line, state->linenr, &patch->old_mode);
|
||||
}
|
||||
|
||||
static int gitdiff_newmode(struct apply_state *state,
|
||||
const char *line,
|
||||
struct patch *patch)
|
||||
{
|
||||
patch->new_mode = strtoul(line, NULL, 8);
|
||||
return 0;
|
||||
return parse_mode_line(line, state->linenr, &patch->new_mode);
|
||||
}
|
||||
|
||||
static int gitdiff_delete(struct apply_state *state,
|
||||
|
@ -1138,7 +1146,7 @@ static int gitdiff_index(struct apply_state *state,
|
|||
memcpy(patch->new_sha1_prefix, line, len);
|
||||
patch->new_sha1_prefix[len] = 0;
|
||||
if (*ptr == ' ')
|
||||
patch->old_mode = strtoul(ptr+1, NULL, 8);
|
||||
return gitdiff_oldmode(state, ptr + 1, patch);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1322,6 +1330,18 @@ static char *git_header_name(struct apply_state *state,
|
|||
}
|
||||
}
|
||||
|
||||
static int check_header_line(struct apply_state *state, struct patch *patch)
|
||||
{
|
||||
int extensions = (patch->is_delete == 1) + (patch->is_new == 1) +
|
||||
(patch->is_rename == 1) + (patch->is_copy == 1);
|
||||
if (extensions > 1)
|
||||
return error(_("inconsistent header lines %d and %d"),
|
||||
patch->extension_linenr, state->linenr);
|
||||
if (extensions && !patch->extension_linenr)
|
||||
patch->extension_linenr = state->linenr;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Verify that we recognize the lines following a git header */
|
||||
static int parse_git_header(struct apply_state *state,
|
||||
const char *line,
|
||||
|
@ -1388,6 +1408,8 @@ static int parse_git_header(struct apply_state *state,
|
|||
res = p->fn(state, line + oplen, patch);
|
||||
if (res < 0)
|
||||
return -1;
|
||||
if (check_header_line(state, patch))
|
||||
return -1;
|
||||
if (res > 0)
|
||||
return offset;
|
||||
break;
|
||||
|
@ -1585,7 +1607,8 @@ static int find_header(struct apply_state *state,
|
|||
patch->old_name = xstrdup(patch->def_name);
|
||||
patch->new_name = xstrdup(patch->def_name);
|
||||
}
|
||||
if (!patch->is_delete && !patch->new_name) {
|
||||
if ((!patch->new_name && !patch->is_delete) ||
|
||||
(!patch->old_name && !patch->is_new)) {
|
||||
error(_("git diff header lacks filename information "
|
||||
"(line %d)"), state->linenr);
|
||||
return -128;
|
||||
|
|
|
@ -13,7 +13,9 @@ test_expect_success setup '
|
|||
echo modified >file &&
|
||||
git diff --stat -p >patch-0.txt &&
|
||||
chmod +x file &&
|
||||
git diff --stat -p >patch-1.txt
|
||||
git diff --stat -p >patch-1.txt &&
|
||||
sed "s/^\(new mode \).*/\1/" <patch-1.txt >patch-empty-mode.txt &&
|
||||
sed "s/^\(new mode \).*/\1garbage/" <patch-1.txt >patch-bogus-mode.txt
|
||||
'
|
||||
|
||||
test_expect_success FILEMODE 'same mode (no index)' '
|
||||
|
@ -59,4 +61,16 @@ test_expect_success FILEMODE 'mode update (index only)' '
|
|||
git ls-files -s file | grep "^100755"
|
||||
'
|
||||
|
||||
test_expect_success FILEMODE 'empty mode is rejected' '
|
||||
git reset --hard &&
|
||||
test_must_fail git apply patch-empty-mode.txt 2>err &&
|
||||
test_i18ngrep "invalid mode" err
|
||||
'
|
||||
|
||||
test_expect_success FILEMODE 'bogus mode is rejected' '
|
||||
git reset --hard &&
|
||||
test_must_fail git apply patch-bogus-mode.txt 2>err &&
|
||||
test_i18ngrep "invalid mode" err
|
||||
'
|
||||
|
||||
test_done
|
||||
|
|
|
@ -35,4 +35,28 @@ test_expect_success 'apply diff with inconsistent filenames in headers' '
|
|||
test_i18ngrep "inconsistent old filename" err
|
||||
'
|
||||
|
||||
test_expect_success 'apply diff with new filename missing from headers' '
|
||||
cat >missing_new_filename.diff <<-\EOF &&
|
||||
diff --git a/f b/f
|
||||
index 0000000..d00491f
|
||||
--- a/f
|
||||
@@ -0,0 +1 @@
|
||||
+1
|
||||
EOF
|
||||
test_must_fail git apply missing_new_filename.diff 2>err &&
|
||||
test_i18ngrep "lacks filename information" err
|
||||
'
|
||||
|
||||
test_expect_success 'apply diff with old filename missing from headers' '
|
||||
cat >missing_old_filename.diff <<-\EOF &&
|
||||
diff --git a/f b/f
|
||||
index d00491f..0000000
|
||||
+++ b/f
|
||||
@@ -1 +0,0 @@
|
||||
-1
|
||||
EOF
|
||||
test_must_fail git apply missing_old_filename.diff 2>err &&
|
||||
test_i18ngrep "lacks filename information" err
|
||||
'
|
||||
|
||||
test_done
|
||||
|
|
|
@ -29,4 +29,22 @@ test_expect_success 'apply exits non-zero with no-op patch' '
|
|||
test_must_fail git apply --check input
|
||||
'
|
||||
|
||||
test_expect_success 'invalid combination: create and copy' '
|
||||
test_must_fail git apply --check - <<-\EOF
|
||||
diff --git a/1 b/2
|
||||
new file mode 100644
|
||||
copy from 1
|
||||
copy to 2
|
||||
EOF
|
||||
'
|
||||
|
||||
test_expect_success 'invalid combination: create and rename' '
|
||||
test_must_fail git apply --check - <<-\EOF
|
||||
diff --git a/1 b/2
|
||||
new file mode 100644
|
||||
rename from 1
|
||||
rename to 2
|
||||
EOF
|
||||
'
|
||||
|
||||
test_done
|
||||
|
|
Загрузка…
Ссылка в новой задаче