Merge branch 'jk/tree-name-and-depth-limit'
We now limit depth of the tree objects and maximum length of pathnames recorded in tree objects. * jk/tree-name-and-depth-limit: lower core.maxTreeDepth default to 2048 tree-diff: respect max_allowed_tree_depth list-objects: respect max_allowed_tree_depth read_tree(): respect max_allowed_tree_depth traverse_trees(): respect max_allowed_tree_depth add core.maxTreeDepth config fsck: detect very large tree pathnames tree-walk: rename "error" variable tree-walk: drop MAX_TRAVERSE_TREES macro tree-walk: reduce stack size for recursive functions
This commit is contained in:
@ -736,3 +736,9 @@ core.abbrev::
|
||||
If set to "no", no abbreviation is made and the object names
|
||||
are shown in their full length.
|
||||
The minimum length is 4.
|
||||
|
||||
core.maxTreeDepth::
|
||||
The maximum depth Git is willing to recurse while traversing a
|
||||
tree (e.g., "a/b/cde/f" has a depth of 4). This is a fail-safe
|
||||
to allow Git to abort cleanly, and should not generally need to
|
||||
be adjusted. The default is 4096.
|
||||
|
@ -103,6 +103,13 @@
|
||||
`hasDotgit`::
|
||||
(WARN) A tree contains an entry named `.git`.
|
||||
|
||||
`largePathname`::
|
||||
(WARN) A tree contains an entry with a very long path name. If
|
||||
the value of `fsck.largePathname` contains a colon, that value
|
||||
is used as the maximum allowable length (e.g., "warn:10" would
|
||||
complain about any path component of 11 or more bytes). The
|
||||
default value is 4096.
|
||||
|
||||
`mailmapSymlink`::
|
||||
(INFO) `.mailmap` is a symlink.
|
||||
|
||||
|
5
config.c
5
config.c
@ -1801,6 +1801,11 @@ static int git_default_core_config(const char *var, const char *value,
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!strcmp(var, "core.maxtreedepth")) {
|
||||
max_allowed_tree_depth = git_config_int(var, value, ctx->kvi);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Add other config variables here and to Documentation/config.txt. */
|
||||
return platform_core_config(var, value, ctx, cb);
|
||||
}
|
||||
|
@ -81,6 +81,7 @@ int merge_log_config = -1;
|
||||
int precomposed_unicode = -1; /* see probe_utf8_pathname_composition() */
|
||||
unsigned long pack_size_limit_cfg;
|
||||
enum log_refs_config log_all_ref_updates = LOG_REFS_UNSET;
|
||||
int max_allowed_tree_depth = 2048;
|
||||
|
||||
#ifndef PROTECT_HFS_DEFAULT
|
||||
#define PROTECT_HFS_DEFAULT 0
|
||||
|
@ -132,6 +132,7 @@ extern size_t packed_git_limit;
|
||||
extern size_t delta_base_cache_limit;
|
||||
extern unsigned long big_file_threshold;
|
||||
extern unsigned long pack_size_limit_cfg;
|
||||
extern int max_allowed_tree_depth;
|
||||
|
||||
/*
|
||||
* Accessors for the core.sharedrepository config which lazy-load the value
|
||||
|
24
fsck.c
24
fsck.c
@ -24,6 +24,8 @@
|
||||
#include "credential.h"
|
||||
#include "help.h"
|
||||
|
||||
static ssize_t max_tree_entry_len = 4096;
|
||||
|
||||
#define STR(x) #x
|
||||
#define MSG_ID(id, msg_type) { STR(id), NULL, NULL, FSCK_##msg_type },
|
||||
static struct {
|
||||
@ -154,15 +156,29 @@ void fsck_set_msg_type(struct fsck_options *options,
|
||||
const char *msg_id_str, const char *msg_type_str)
|
||||
{
|
||||
int msg_id = parse_msg_id(msg_id_str);
|
||||
enum fsck_msg_type msg_type = parse_msg_type(msg_type_str);
|
||||
char *to_free = NULL;
|
||||
enum fsck_msg_type msg_type;
|
||||
|
||||
if (msg_id < 0)
|
||||
die("Unhandled message id: %s", msg_id_str);
|
||||
|
||||
if (msg_id == FSCK_MSG_LARGE_PATHNAME) {
|
||||
const char *colon = strchr(msg_type_str, ':');
|
||||
if (colon) {
|
||||
msg_type_str = to_free =
|
||||
xmemdupz(msg_type_str, colon - msg_type_str);
|
||||
colon++;
|
||||
if (!git_parse_ssize_t(colon, &max_tree_entry_len))
|
||||
die("unable to parse max tree entry len: %s", colon);
|
||||
}
|
||||
}
|
||||
msg_type = parse_msg_type(msg_type_str);
|
||||
|
||||
if (msg_type != FSCK_ERROR && msg_id_info[msg_id].msg_type == FSCK_FATAL)
|
||||
die("Cannot demote %s to %s", msg_id_str, msg_type_str);
|
||||
|
||||
fsck_set_msg_type_from_ids(options, msg_id, msg_type);
|
||||
free(to_free);
|
||||
}
|
||||
|
||||
void fsck_set_msg_types(struct fsck_options *options, const char *values)
|
||||
@ -578,6 +594,7 @@ static int fsck_tree(const struct object_id *tree_oid,
|
||||
int has_bad_modes = 0;
|
||||
int has_dup_entries = 0;
|
||||
int not_properly_sorted = 0;
|
||||
int has_large_name = 0;
|
||||
struct tree_desc desc;
|
||||
unsigned o_mode;
|
||||
const char *o_name;
|
||||
@ -607,6 +624,7 @@ static int fsck_tree(const struct object_id *tree_oid,
|
||||
has_dotdot |= !strcmp(name, "..");
|
||||
has_dotgit |= is_hfs_dotgit(name) || is_ntfs_dotgit(name);
|
||||
has_zero_pad |= *(char *)desc.buffer == '0';
|
||||
has_large_name |= tree_entry_len(&desc.entry) > max_tree_entry_len;
|
||||
|
||||
if (is_hfs_dotgitmodules(name) || is_ntfs_dotgitmodules(name)) {
|
||||
if (!S_ISLNK(mode))
|
||||
@ -749,6 +767,10 @@ static int fsck_tree(const struct object_id *tree_oid,
|
||||
retval += report(options, tree_oid, OBJ_TREE,
|
||||
FSCK_MSG_TREE_NOT_SORTED,
|
||||
"not properly sorted");
|
||||
if (has_large_name)
|
||||
retval += report(options, tree_oid, OBJ_TREE,
|
||||
FSCK_MSG_LARGE_PATHNAME,
|
||||
"contains excessively large pathname");
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
1
fsck.h
1
fsck.h
@ -73,6 +73,7 @@ enum fsck_msg_type {
|
||||
FUNC(NULL_SHA1, WARN) \
|
||||
FUNC(ZERO_PADDED_FILEMODE, WARN) \
|
||||
FUNC(NUL_IN_COMMIT, WARN) \
|
||||
FUNC(LARGE_PATHNAME, WARN) \
|
||||
/* infos (reported as warnings, but ignored by default) */ \
|
||||
FUNC(BAD_FILEMODE, INFO) \
|
||||
FUNC(GITMODULES_PARSE, INFO) \
|
||||
|
@ -14,6 +14,7 @@
|
||||
#include "packfile.h"
|
||||
#include "object-store-ll.h"
|
||||
#include "trace.h"
|
||||
#include "environment.h"
|
||||
|
||||
struct traversal_context {
|
||||
struct rev_info *revs;
|
||||
@ -21,6 +22,7 @@ struct traversal_context {
|
||||
show_commit_fn show_commit;
|
||||
void *show_data;
|
||||
struct filter *filter;
|
||||
int depth;
|
||||
};
|
||||
|
||||
static void show_commit(struct traversal_context *ctx,
|
||||
@ -118,7 +120,9 @@ static void process_tree_contents(struct traversal_context *ctx,
|
||||
entry.path, oid_to_hex(&tree->object.oid));
|
||||
}
|
||||
t->object.flags |= NOT_USER_GIVEN;
|
||||
ctx->depth++;
|
||||
process_tree(ctx, t, base, entry.path);
|
||||
ctx->depth--;
|
||||
}
|
||||
else if (S_ISGITLINK(entry.mode))
|
||||
; /* ignore gitlink */
|
||||
@ -156,6 +160,9 @@ static void process_tree(struct traversal_context *ctx,
|
||||
!revs->include_check_obj(&tree->object, revs->include_check_data))
|
||||
return;
|
||||
|
||||
if (ctx->depth > max_allowed_tree_depth)
|
||||
die("exceeded maximum allowed tree depth");
|
||||
|
||||
failed_parse = parse_tree_gently(tree, 1);
|
||||
if (failed_parse) {
|
||||
if (revs->ignore_missing_links)
|
||||
@ -349,6 +356,7 @@ static void traverse_non_commits(struct traversal_context *ctx,
|
||||
if (!path)
|
||||
path = "";
|
||||
if (obj->type == OBJ_TREE) {
|
||||
ctx->depth = 0;
|
||||
process_tree(ctx, (struct tree *)obj, base, path);
|
||||
continue;
|
||||
}
|
||||
|
@ -391,7 +391,7 @@ void expand_index(struct index_state *istate, struct pattern_list *pl)
|
||||
strbuf_setlen(&base, 0);
|
||||
strbuf_add(&base, ce->name, strlen(ce->name));
|
||||
|
||||
read_tree_at(istate->repo, tree, &base, &ps,
|
||||
read_tree_at(istate->repo, tree, &base, 0, &ps,
|
||||
add_path_to_index, &ctx);
|
||||
|
||||
/* free directory entries. full entries are re-used */
|
||||
|
@ -589,6 +589,16 @@ test_expect_success 'fsck notices submodule entry pointing to null sha1' '
|
||||
)
|
||||
'
|
||||
|
||||
test_expect_success 'fsck notices excessively large tree entry name' '
|
||||
git init large-name &&
|
||||
(
|
||||
cd large-name &&
|
||||
test_commit a-long-name &&
|
||||
git -c fsck.largePathname=warn:10 fsck 2>out &&
|
||||
grep "warning.*large pathname" out
|
||||
)
|
||||
'
|
||||
|
||||
while read name path pretty; do
|
||||
while read mode type; do
|
||||
: ${pretty:=$path}
|
||||
|
93
t/t6700-tree-depth.sh
Executable file
93
t/t6700-tree-depth.sh
Executable file
@ -0,0 +1,93 @@
|
||||
#!/bin/sh
|
||||
|
||||
test_description='handling of deep trees in various commands'
|
||||
. ./test-lib.sh
|
||||
|
||||
# We'll test against two depths here: a small one that will let us check the
|
||||
# behavior of the config setting easily, and a large one that should be
|
||||
# forbidden by default. Testing the default depth will let us know whether our
|
||||
# default is enough to prevent segfaults on systems that run the tests.
|
||||
small_depth=50
|
||||
big_depth=4100
|
||||
|
||||
small_ok="-c core.maxtreedepth=$small_depth"
|
||||
small_no="-c core.maxtreedepth=$((small_depth-1))"
|
||||
|
||||
# usage: mkdeep <name> <depth>
|
||||
# Create a tag <name> containing a file whose path has depth <depth>.
|
||||
#
|
||||
# We'll use fast-import here for two reasons:
|
||||
#
|
||||
# 1. It's faster than creating $big_depth tree objects.
|
||||
#
|
||||
# 2. As we tighten tree limits, it's more likely to allow large sizes
|
||||
# than trying to stuff a deep path into the index.
|
||||
mkdeep () {
|
||||
{
|
||||
echo "commit refs/tags/$1" &&
|
||||
echo "committer foo <foo@example.com> 1234 -0000" &&
|
||||
echo "data <<EOF" &&
|
||||
echo "the commit message" &&
|
||||
echo "EOF" &&
|
||||
|
||||
printf 'M 100644 inline ' &&
|
||||
i=0 &&
|
||||
while test $i -lt $2
|
||||
do
|
||||
printf 'a/'
|
||||
i=$((i+1))
|
||||
done &&
|
||||
echo "file" &&
|
||||
|
||||
echo "data <<EOF" &&
|
||||
echo "the file contents" &&
|
||||
echo "EOF" &&
|
||||
echo
|
||||
} | git fast-import
|
||||
}
|
||||
|
||||
test_expect_success 'create small tree' '
|
||||
mkdeep small $small_depth
|
||||
'
|
||||
|
||||
test_expect_success 'create big tree' '
|
||||
mkdeep big $big_depth
|
||||
'
|
||||
|
||||
test_expect_success 'limit recursion of git-archive' '
|
||||
git $small_ok archive small >/dev/null &&
|
||||
test_must_fail git $small_no archive small >/dev/null
|
||||
'
|
||||
|
||||
test_expect_success 'default limit for git-archive fails gracefully' '
|
||||
test_must_fail git archive big >/dev/null
|
||||
'
|
||||
|
||||
test_expect_success 'limit recursion of ls-tree -r' '
|
||||
git $small_ok ls-tree -r small &&
|
||||
test_must_fail git $small_no ls-tree -r small
|
||||
'
|
||||
|
||||
test_expect_success 'default limit for ls-tree fails gracefully' '
|
||||
test_must_fail git ls-tree -r big >/dev/null
|
||||
'
|
||||
|
||||
test_expect_success 'limit recursion of rev-list --objects' '
|
||||
git $small_ok rev-list --objects small >/dev/null &&
|
||||
test_must_fail git $small_no rev-list --objects small >/dev/null
|
||||
'
|
||||
|
||||
test_expect_success 'default limit for rev-list fails gracefully' '
|
||||
test_must_fail git rev-list --objects big >/dev/null
|
||||
'
|
||||
|
||||
test_expect_success 'limit recursion of diff-tree -r' '
|
||||
git $small_ok diff-tree -r $EMPTY_TREE small &&
|
||||
test_must_fail git $small_no diff-tree -r $EMPTY_TREE small
|
||||
'
|
||||
|
||||
test_expect_success 'default limit for diff-tree fails gracefully' '
|
||||
test_must_fail git diff-tree -r $EMPTY_TREE big
|
||||
'
|
||||
|
||||
test_done
|
23
tree-diff.c
23
tree-diff.c
@ -7,6 +7,7 @@
|
||||
#include "hash.h"
|
||||
#include "tree.h"
|
||||
#include "tree-walk.h"
|
||||
#include "environment.h"
|
||||
|
||||
/*
|
||||
* Some mode bits are also used internally for computations.
|
||||
@ -45,7 +46,8 @@
|
||||
static struct combine_diff_path *ll_diff_tree_paths(
|
||||
struct combine_diff_path *p, const struct object_id *oid,
|
||||
const struct object_id **parents_oid, int nparent,
|
||||
struct strbuf *base, struct diff_options *opt);
|
||||
struct strbuf *base, struct diff_options *opt,
|
||||
int depth);
|
||||
static void ll_diff_tree_oid(const struct object_id *old_oid,
|
||||
const struct object_id *new_oid,
|
||||
struct strbuf *base, struct diff_options *opt);
|
||||
@ -196,7 +198,7 @@ static struct combine_diff_path *path_appendnew(struct combine_diff_path *last,
|
||||
static struct combine_diff_path *emit_path(struct combine_diff_path *p,
|
||||
struct strbuf *base, struct diff_options *opt, int nparent,
|
||||
struct tree_desc *t, struct tree_desc *tp,
|
||||
int imin)
|
||||
int imin, int depth)
|
||||
{
|
||||
unsigned short mode;
|
||||
const char *path;
|
||||
@ -302,7 +304,8 @@ static struct combine_diff_path *emit_path(struct combine_diff_path *p,
|
||||
|
||||
strbuf_add(base, path, pathlen);
|
||||
strbuf_addch(base, '/');
|
||||
p = ll_diff_tree_paths(p, oid, parents_oid, nparent, base, opt);
|
||||
p = ll_diff_tree_paths(p, oid, parents_oid, nparent, base, opt,
|
||||
depth + 1);
|
||||
FAST_ARRAY_FREE(parents_oid, nparent);
|
||||
}
|
||||
|
||||
@ -423,12 +426,16 @@ static inline void update_tp_entries(struct tree_desc *tp, int nparent)
|
||||
static struct combine_diff_path *ll_diff_tree_paths(
|
||||
struct combine_diff_path *p, const struct object_id *oid,
|
||||
const struct object_id **parents_oid, int nparent,
|
||||
struct strbuf *base, struct diff_options *opt)
|
||||
struct strbuf *base, struct diff_options *opt,
|
||||
int depth)
|
||||
{
|
||||
struct tree_desc t, *tp;
|
||||
void *ttree, **tptree;
|
||||
int i;
|
||||
|
||||
if (depth > max_allowed_tree_depth)
|
||||
die("exceeded maximum allowed tree depth");
|
||||
|
||||
FAST_ARRAY_ALLOC(tp, nparent);
|
||||
FAST_ARRAY_ALLOC(tptree, nparent);
|
||||
|
||||
@ -522,7 +529,7 @@ static struct combine_diff_path *ll_diff_tree_paths(
|
||||
|
||||
/* D += {δ(t,pi) if pi=p[imin]; "+a" if pi > p[imin]} */
|
||||
p = emit_path(p, base, opt, nparent,
|
||||
&t, tp, imin);
|
||||
&t, tp, imin, depth);
|
||||
|
||||
skip_emit_t_tp:
|
||||
/* t↓, ∀ pi=p[imin] pi↓ */
|
||||
@ -534,7 +541,7 @@ static struct combine_diff_path *ll_diff_tree_paths(
|
||||
else if (cmp < 0) {
|
||||
/* D += "+t" */
|
||||
p = emit_path(p, base, opt, nparent,
|
||||
&t, /*tp=*/NULL, -1);
|
||||
&t, /*tp=*/NULL, -1, depth);
|
||||
|
||||
/* t↓ */
|
||||
update_tree_entry(&t);
|
||||
@ -550,7 +557,7 @@ static struct combine_diff_path *ll_diff_tree_paths(
|
||||
}
|
||||
|
||||
p = emit_path(p, base, opt, nparent,
|
||||
/*t=*/NULL, tp, imin);
|
||||
/*t=*/NULL, tp, imin, depth);
|
||||
|
||||
skip_emit_tp:
|
||||
/* ∀ pi=p[imin] pi↓ */
|
||||
@ -572,7 +579,7 @@ struct combine_diff_path *diff_tree_paths(
|
||||
const struct object_id **parents_oid, int nparent,
|
||||
struct strbuf *base, struct diff_options *opt)
|
||||
{
|
||||
p = ll_diff_tree_paths(p, oid, parents_oid, nparent, base, opt);
|
||||
p = ll_diff_tree_paths(p, oid, parents_oid, nparent, base, opt, 0);
|
||||
|
||||
/*
|
||||
* free pre-allocated last element, if any
|
||||
|
20
tree-walk.c
20
tree-walk.c
@ -9,6 +9,7 @@
|
||||
#include "tree.h"
|
||||
#include "pathspec.h"
|
||||
#include "json-writer.h"
|
||||
#include "environment.h"
|
||||
|
||||
static const char *get_mode(const char *str, unsigned int *modep)
|
||||
{
|
||||
@ -441,22 +442,25 @@ int traverse_trees(struct index_state *istate,
|
||||
int n, struct tree_desc *t,
|
||||
struct traverse_info *info)
|
||||
{
|
||||
int error = 0;
|
||||
struct name_entry entry[MAX_TRAVERSE_TREES];
|
||||
int ret = 0;
|
||||
struct name_entry *entry;
|
||||
int i;
|
||||
struct tree_desc_x tx[ARRAY_SIZE(entry)];
|
||||
struct tree_desc_x *tx;
|
||||
struct strbuf base = STRBUF_INIT;
|
||||
int interesting = 1;
|
||||
char *traverse_path;
|
||||
|
||||
if (traverse_trees_cur_depth > max_allowed_tree_depth)
|
||||
return error("exceeded maximum allowed tree depth");
|
||||
|
||||
traverse_trees_count++;
|
||||
traverse_trees_cur_depth++;
|
||||
|
||||
if (traverse_trees_cur_depth > traverse_trees_max_depth)
|
||||
traverse_trees_max_depth = traverse_trees_cur_depth;
|
||||
|
||||
if (n >= ARRAY_SIZE(entry))
|
||||
BUG("traverse_trees() called with too many trees (%d)", n);
|
||||
ALLOC_ARRAY(entry, n);
|
||||
ALLOC_ARRAY(tx, n);
|
||||
|
||||
for (i = 0; i < n; i++) {
|
||||
tx[i].d = t[i];
|
||||
@ -539,7 +543,7 @@ int traverse_trees(struct index_state *istate,
|
||||
if (interesting) {
|
||||
trees_used = info->fn(n, mask, dirmask, entry, info);
|
||||
if (trees_used < 0) {
|
||||
error = trees_used;
|
||||
ret = trees_used;
|
||||
if (!info->show_all_errors)
|
||||
break;
|
||||
}
|
||||
@ -551,12 +555,14 @@ int traverse_trees(struct index_state *istate,
|
||||
}
|
||||
for (i = 0; i < n; i++)
|
||||
free_extended_entry(tx + i);
|
||||
free(tx);
|
||||
free(entry);
|
||||
free(traverse_path);
|
||||
info->traverse_path = NULL;
|
||||
strbuf_release(&base);
|
||||
|
||||
traverse_trees_cur_depth--;
|
||||
return error;
|
||||
return ret;
|
||||
}
|
||||
|
||||
struct dir_state {
|
||||
|
@ -6,8 +6,6 @@
|
||||
struct index_state;
|
||||
struct repository;
|
||||
|
||||
#define MAX_TRAVERSE_TREES 8
|
||||
|
||||
/**
|
||||
* The tree walking API is used to traverse and inspect trees.
|
||||
*/
|
||||
|
9
tree.c
9
tree.c
@ -10,11 +10,13 @@
|
||||
#include "alloc.h"
|
||||
#include "tree-walk.h"
|
||||
#include "repository.h"
|
||||
#include "environment.h"
|
||||
|
||||
const char *tree_type = "tree";
|
||||
|
||||
int read_tree_at(struct repository *r,
|
||||
struct tree *tree, struct strbuf *base,
|
||||
int depth,
|
||||
const struct pathspec *pathspec,
|
||||
read_tree_fn_t fn, void *context)
|
||||
{
|
||||
@ -24,6 +26,9 @@ int read_tree_at(struct repository *r,
|
||||
int len, oldlen = base->len;
|
||||
enum interesting retval = entry_not_interesting;
|
||||
|
||||
if (depth > max_allowed_tree_depth)
|
||||
return error("exceeded maximum allowed tree depth");
|
||||
|
||||
if (parse_tree(tree))
|
||||
return -1;
|
||||
|
||||
@ -74,7 +79,7 @@ int read_tree_at(struct repository *r,
|
||||
strbuf_add(base, entry.path, len);
|
||||
strbuf_addch(base, '/');
|
||||
retval = read_tree_at(r, lookup_tree(r, &oid),
|
||||
base, pathspec,
|
||||
base, depth + 1, pathspec,
|
||||
fn, context);
|
||||
strbuf_setlen(base, oldlen);
|
||||
if (retval)
|
||||
@ -89,7 +94,7 @@ int read_tree(struct repository *r,
|
||||
read_tree_fn_t fn, void *context)
|
||||
{
|
||||
struct strbuf sb = STRBUF_INIT;
|
||||
int ret = read_tree_at(r, tree, &sb, pathspec, fn, context);
|
||||
int ret = read_tree_at(r, tree, &sb, 0, pathspec, fn, context);
|
||||
strbuf_release(&sb);
|
||||
return ret;
|
||||
}
|
||||
|
1
tree.h
1
tree.h
@ -44,6 +44,7 @@ typedef int (*read_tree_fn_t)(const struct object_id *, struct strbuf *, const c
|
||||
|
||||
int read_tree_at(struct repository *r,
|
||||
struct tree *tree, struct strbuf *base,
|
||||
int depth,
|
||||
const struct pathspec *pathspec,
|
||||
read_tree_fn_t fn, void *context);
|
||||
|
||||
|
@ -864,8 +864,8 @@ static int traverse_trees_recursive(int n, unsigned long dirmask,
|
||||
struct unpack_trees_options *o = info->data;
|
||||
int i, ret, bottom;
|
||||
int nr_buf = 0;
|
||||
struct tree_desc t[MAX_UNPACK_TREES];
|
||||
void *buf[MAX_UNPACK_TREES];
|
||||
struct tree_desc *t;
|
||||
void **buf;
|
||||
struct traverse_info newinfo;
|
||||
struct name_entry *p;
|
||||
int nr_entries;
|
||||
@ -902,6 +902,9 @@ static int traverse_trees_recursive(int n, unsigned long dirmask,
|
||||
newinfo.pathlen = st_add3(newinfo.pathlen, tree_entry_len(p), 1);
|
||||
newinfo.df_conflicts |= df_conflicts;
|
||||
|
||||
ALLOC_ARRAY(t, n);
|
||||
ALLOC_ARRAY(buf, n);
|
||||
|
||||
/*
|
||||
* Fetch the tree from the ODB for each peer directory in the
|
||||
* n commits.
|
||||
@ -937,6 +940,8 @@ static int traverse_trees_recursive(int n, unsigned long dirmask,
|
||||
|
||||
for (i = 0; i < nr_buf; i++)
|
||||
free(buf[i]);
|
||||
free(buf);
|
||||
free(t);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -7,7 +7,7 @@
|
||||
#include "string-list.h"
|
||||
#include "tree-walk.h"
|
||||
|
||||
#define MAX_UNPACK_TREES MAX_TRAVERSE_TREES
|
||||
#define MAX_UNPACK_TREES 8
|
||||
|
||||
struct cache_entry;
|
||||
struct unpack_trees_options;
|
||||
|
@ -739,7 +739,7 @@ static void wt_status_collect_changes_initial(struct wt_status *s)
|
||||
ps.max_depth = -1;
|
||||
|
||||
strbuf_add(&base, ce->name, ce->ce_namelen);
|
||||
read_tree_at(istate->repo, tree, &base, &ps,
|
||||
read_tree_at(istate->repo, tree, &base, 0, &ps,
|
||||
add_file_to_list, s);
|
||||
continue;
|
||||
}
|
||||
|
Reference in New Issue
Block a user