diff options
Diffstat (limited to 'upload-pack.c')
-rw-r--r-- | upload-pack.c | 104 |
1 files changed, 104 insertions, 0 deletions
diff --git a/upload-pack.c b/upload-pack.c index d087113d23..80ad9a38d8 100644 --- a/upload-pack.c +++ b/upload-pack.c @@ -88,6 +88,7 @@ struct upload_pack_data { enum allow_uor allow_uor; struct list_objects_filter_options filter_options; + struct string_list allowed_filters; struct packet_writer writer; @@ -103,6 +104,8 @@ struct upload_pack_data { unsigned no_progress : 1; unsigned use_include_tag : 1; unsigned allow_filter : 1; + unsigned allow_filter_fallback : 1; + unsigned long tree_filter_max_depth; unsigned done : 1; /* v2 only */ unsigned allow_ref_in_want : 1; /* v2 only */ @@ -120,6 +123,7 @@ static void upload_pack_data_init(struct upload_pack_data *data) struct string_list deepen_not = STRING_LIST_INIT_DUP; struct string_list uri_protocols = STRING_LIST_INIT_DUP; struct object_array extra_edge_obj = OBJECT_ARRAY_INIT; + struct string_list allowed_filters = STRING_LIST_INIT_DUP; memset(data, 0, sizeof(*data)); data->symref = symref; @@ -131,6 +135,9 @@ static void upload_pack_data_init(struct upload_pack_data *data) data->deepen_not = deepen_not; data->uri_protocols = uri_protocols; data->extra_edge_obj = extra_edge_obj; + data->allowed_filters = allowed_filters; + data->allow_filter_fallback = 1; + data->tree_filter_max_depth = ULONG_MAX; packet_writer_init(&data->writer, 1); data->keepalive = 5; @@ -147,6 +154,7 @@ static void upload_pack_data_clear(struct upload_pack_data *data) string_list_clear(&data->deepen_not, 0); object_array_clear(&data->extra_edge_obj); list_objects_filter_release(&data->filter_options); + string_list_clear(&data->allowed_filters, 1); free((char *)data->pack_objects_hook); } @@ -983,6 +991,63 @@ static int process_deepen_not(const char *line, struct string_list *deepen_not, return 0; } +NORETURN __attribute__((format(printf,2,3))) +static void send_err_and_die(struct upload_pack_data *data, + const char *fmt, ...) +{ + struct strbuf buf = STRBUF_INIT; + va_list ap; + + va_start(ap, fmt); + strbuf_vaddf(&buf, fmt, ap); + va_end(ap); + + packet_writer_error(&data->writer, "%s", buf.buf); + die("%s", buf.buf); +} + +static void check_one_filter(struct upload_pack_data *data, + struct list_objects_filter_options *opts) +{ + const char *key = list_object_filter_config_name(opts->choice); + struct string_list_item *item = string_list_lookup(&data->allowed_filters, + key); + int allowed; + + if (item) + allowed = (intptr_t)item->util; + else + allowed = data->allow_filter_fallback; + + if (!allowed) + send_err_and_die(data, "filter '%s' not supported", key); + + if (opts->choice == LOFC_TREE_DEPTH && + opts->tree_exclude_depth > data->tree_filter_max_depth) + send_err_and_die(data, + "tree filter allows max depth %lu, but got %lu", + data->tree_filter_max_depth, + opts->tree_exclude_depth); +} + +static void check_filter_recurse(struct upload_pack_data *data, + struct list_objects_filter_options *opts) +{ + size_t i; + + check_one_filter(data, opts); + if (opts->choice != LOFC_COMBINE) + return; + + for (i = 0; i < opts->sub_nr; i++) + check_filter_recurse(data, &opts->sub[i]); +} + +static void die_if_using_banned_filter(struct upload_pack_data *data) +{ + check_filter_recurse(data, &data->filter_options); +} + static void receive_needs(struct upload_pack_data *data, struct packet_reader *reader) { @@ -1013,6 +1078,7 @@ static void receive_needs(struct upload_pack_data *data, die("git upload-pack: filtering capability not negotiated"); list_objects_filter_die_if_populated(&data->filter_options); parse_list_objects_filter(&data->filter_options, arg); + die_if_using_banned_filter(data); continue; } @@ -1170,6 +1236,41 @@ static int find_symref(const char *refname, const struct object_id *oid, return 0; } +static int parse_object_filter_config(const char *var, const char *value, + struct upload_pack_data *data) +{ + struct strbuf buf = STRBUF_INIT; + const char *sub, *key; + size_t sub_len; + + if (parse_config_key(var, "uploadpackfilter", &sub, &sub_len, &key)) + return 0; + + if (!sub) { + if (!strcmp(key, "allow")) + data->allow_filter_fallback = git_config_bool(var, value); + return 0; + } + + strbuf_add(&buf, sub, sub_len); + + if (!strcmp(key, "allow")) + string_list_insert(&data->allowed_filters, buf.buf)->util = + (void *)(intptr_t)git_config_bool(var, value); + else if (!strcmp(buf.buf, "tree") && !strcmp(key, "maxdepth")) { + if (!value) { + strbuf_release(&buf); + return config_error_nonbool(var); + } + string_list_insert(&data->allowed_filters, buf.buf)->util = + (void *)(intptr_t)1; + data->tree_filter_max_depth = git_config_ulong(var, value); + } + + strbuf_release(&buf); + return 0; +} + static int upload_pack_config(const char *var, const char *value, void *cb_data) { struct upload_pack_data *data = cb_data; @@ -1209,6 +1310,8 @@ static int upload_pack_config(const char *var, const char *value, void *cb_data) return git_config_string(&data->pack_objects_hook, var, value); } + parse_object_filter_config(var, value, data); + return parse_hide_refs_config(var, value, "uploadpack"); } @@ -1389,6 +1492,7 @@ static void process_args(struct packet_reader *request, if (data->allow_filter && skip_prefix(arg, "filter ", &p)) { list_objects_filter_die_if_populated(&data->filter_options); parse_list_objects_filter(&data->filter_options, p); + die_if_using_banned_filter(data); continue; } |