#include "cache.h"
#include "config.h"
+#include "environment.h"
+#include "gettext.h"
+#include "hex.h"
#include "refs.h"
#include "pkt-line.h"
#include "sideband.h"
struct object_array have_obj;
struct oid_array haves; /* v2 only */
struct string_list wanted_refs; /* v2 only */
+ struct string_list hidden_refs;
struct object_array shallows;
struct string_list deepen_not;
{
struct string_list symref = STRING_LIST_INIT_DUP;
struct string_list wanted_refs = STRING_LIST_INIT_DUP;
+ struct string_list hidden_refs = STRING_LIST_INIT_DUP;
struct object_array want_obj = OBJECT_ARRAY_INIT;
struct object_array have_obj = OBJECT_ARRAY_INIT;
struct oid_array haves = OID_ARRAY_INIT;
memset(data, 0, sizeof(*data));
data->symref = symref;
data->wanted_refs = wanted_refs;
+ data->hidden_refs = hidden_refs;
data->want_obj = want_obj;
data->have_obj = have_obj;
data->haves = haves;
data->allow_filter_fallback = 1;
data->tree_filter_max_depth = ULONG_MAX;
packet_writer_init(&data->writer, 1);
+ list_objects_filter_init(&data->filter_options);
data->keepalive = 5;
data->advertise_sid = 0;
{
string_list_clear(&data->symref, 1);
string_list_clear(&data->wanted_refs, 1);
+ string_list_clear(&data->hidden_refs, 0);
object_array_clear(&data->want_obj);
object_array_clear(&data->have_obj);
oid_array_clear(&data->haves);
}
struct output_state {
- char buffer[8193];
+ /*
+ * We do writes no bigger than LARGE_PACKET_DATA_MAX - 1, because with
+ * sideband-64k the band designator takes up 1 byte of space. Because
+ * relay_pack_data keeps the last byte to itself, we make the buffer 1
+ * byte bigger than the intended maximum write size.
+ */
+ char buffer[(LARGE_PACKET_DATA_MAX - 1) + 1];
int used;
unsigned packfile_uris_started : 1;
unsigned packfile_started : 1;
const struct string_list *uri_protocols)
{
struct child_process pack_objects = CHILD_PROCESS_INIT;
- struct output_state output_state = { { 0 } };
+ struct output_state *output_state = xcalloc(1, sizeof(struct output_state));
char progress[128];
char abort_msg[] = "aborting due to possible repository "
"corruption on the remote side.";
}
if (0 <= pu && (pfd[pu].revents & (POLLIN|POLLHUP))) {
int result = relay_pack_data(pack_objects.out,
- &output_state,
+ output_state,
pack_data->use_sideband,
!!uri_protocols);
}
/* flush the data */
- if (output_state.used > 0) {
- send_client_data(1, output_state.buffer, output_state.used,
+ if (output_state->used > 0) {
+ send_client_data(1, output_state->buffer, output_state->used,
pack_data->use_sideband);
fprintf(stderr, "flushed.\n");
}
+ free(output_state);
if (pack_data->use_sideband)
packet_flush(1);
return;
fail:
+ free(output_state);
send_client_data(3, abort_msg, sizeof(abort_msg),
pack_data->use_sideband);
die("git upload-pack: %s", abort_msg);
struct object_array *reachable,
enum allow_uor allow_uor)
{
- static const char *argv[] = {
- "rev-list", "--stdin", NULL,
- };
struct object *o;
FILE *cmd_in = NULL;
int i;
- cmd->argv = argv;
+ strvec_pushl(&cmd->args, "rev-list", "--stdin", NULL);
cmd->git_cmd = 1;
cmd->no_stderr = 1;
cmd->in = -1;
* Checking for reachable shallows requires that our refs be
* marked with OUR_REF.
*/
- head_ref_namespaced(check_ref, NULL);
- for_each_namespaced_ref(check_ref, NULL);
+ head_ref_namespaced(check_ref, data);
+ for_each_namespaced_ref(check_ref, data);
get_reachable_list(data, &reachable_shallows);
result = get_shallow_commits(&reachable_shallows,
/* return non-zero if the ref is hidden, otherwise 0 */
static int mark_our_ref(const char *refname, const char *refname_full,
- const struct object_id *oid)
+ const struct object_id *oid, const struct string_list *hidden_refs)
{
struct object *o = lookup_unknown_object(the_repository, oid);
- if (ref_is_hidden(refname, refname_full)) {
+ if (ref_is_hidden(refname, refname_full, hidden_refs)) {
o->flags |= HIDDEN_REF;
return 1;
}
}
static int check_ref(const char *refname_full, const struct object_id *oid,
- int flag, void *cb_data)
+ int flag UNUSED, void *cb_data)
{
const char *refname = strip_namespace(refname_full);
+ struct upload_pack_data *data = cb_data;
- mark_our_ref(refname, refname_full, oid);
+ mark_our_ref(refname, refname_full, oid, &data->hidden_refs);
return 0;
}
}
static int send_ref(const char *refname, const struct object_id *oid,
- int flag, void *cb_data)
+ int flag UNUSED, void *cb_data)
{
static const char *capabilities = "multi_ack thin-pack side-band"
" side-band-64k ofs-delta shallow deepen-since deepen-not"
struct object_id peeled;
struct upload_pack_data *data = cb_data;
- if (mark_our_ref(refname_nons, refname, oid))
+ if (mark_our_ref(refname_nons, refname, oid, &data->hidden_refs))
return 0;
if (capabilities) {
format_symref_info(&symref_info, &data->symref);
format_session_id(&session_id, data);
- packet_write_fmt(1, "%s %s%c%s%s%s%s%s%s%s object-format=%s agent=%s\n",
+ packet_fwrite_fmt(stdout, "%s %s%c%s%s%s%s%s%s%s object-format=%s agent=%s\n",
oid_to_hex(oid), refname_nons,
0, capabilities,
(data->allow_uor & ALLOW_TIP_SHA1) ?
" allow-tip-sha1-in-want" : "",
(data->allow_uor & ALLOW_REACHABLE_SHA1) ?
" allow-reachable-sha1-in-want" : "",
- data->stateless_rpc ? " no-done" : "",
+ data->no_done ? " no-done" : "",
symref_info.buf,
data->allow_filter ? " filter" : "",
session_id.buf,
strbuf_release(&symref_info);
strbuf_release(&session_id);
} else {
- packet_write_fmt(1, "%s %s\n", oid_to_hex(oid), refname_nons);
+ packet_fwrite_fmt(stdout, "%s %s\n", oid_to_hex(oid), refname_nons);
}
capabilities = NULL;
if (!peel_iterated_oid(oid, &peeled))
- packet_write_fmt(1, "%s %s^{}\n", oid_to_hex(&peeled), refname_nons);
+ packet_fwrite_fmt(stdout, "%s %s^{}\n", oid_to_hex(&peeled), refname_nons);
return 0;
}
-static int find_symref(const char *refname, const struct object_id *oid,
+static int find_symref(const char *refname,
+ const struct object_id *oid UNUSED,
int flag, void *cb_data)
{
const char *symref_target;
data->advertise_sid = git_config_bool(var, value);
}
- if (current_config_scope() != CONFIG_SCOPE_LOCAL &&
- current_config_scope() != CONFIG_SCOPE_WORKTREE) {
- if (!strcmp("uploadpack.packobjectshook", var))
- return git_config_string(&data->pack_objects_hook, var, value);
- }
-
if (parse_object_filter_config(var, value, data) < 0)
return -1;
- return parse_hide_refs_config(var, value, "uploadpack");
+ return parse_hide_refs_config(var, value, "uploadpack", &data->hidden_refs);
+}
+
+static int upload_pack_protected_config(const char *var, const char *value, void *cb_data)
+{
+ struct upload_pack_data *data = cb_data;
+
+ if (!strcmp("uploadpack.packobjectshook", var))
+ return git_config_string(&data->pack_objects_hook, var, value);
+ return 0;
+}
+
+static void get_upload_pack_config(struct upload_pack_data *data)
+{
+ git_config(upload_pack_config, data);
+ git_protected_config(upload_pack_protected_config, data);
}
-void upload_pack(struct upload_pack_options *options)
+void upload_pack(const int advertise_refs, const int stateless_rpc,
+ const int timeout)
{
struct packet_reader reader;
struct upload_pack_data data;
upload_pack_data_init(&data);
+ get_upload_pack_config(&data);
- git_config(upload_pack_config, &data);
-
- data.stateless_rpc = options->stateless_rpc;
- data.daemon_mode = options->daemon_mode;
- data.timeout = options->timeout;
+ data.stateless_rpc = stateless_rpc;
+ data.timeout = timeout;
+ if (data.timeout)
+ data.daemon_mode = 1;
head_ref_namespaced(find_symref, &data.symref);
- if (options->advertise_refs || !data.stateless_rpc) {
+ if (advertise_refs || !data.stateless_rpc) {
reset_timeout(data.timeout);
+ if (advertise_refs)
+ data.no_done = 1;
head_ref_namespaced(send_ref, &data);
for_each_namespaced_ref(send_ref, &data);
+ /*
+ * fflush stdout before calling advertise_shallow_grafts because send_ref
+ * uses stdio.
+ */
+ fflush_or_die(stdout);
advertise_shallow_grafts(1);
packet_flush(1);
} else {
- head_ref_namespaced(check_ref, NULL);
- for_each_namespaced_ref(check_ref, NULL);
+ head_ref_namespaced(check_ref, &data);
+ for_each_namespaced_ref(check_ref, &data);
}
- if (!options->advertise_refs) {
+ if (!advertise_refs) {
packet_reader_init(&reader, 0, NULL, 0,
PACKET_READ_CHOMP_NEWLINE |
PACKET_READ_DIE_ON_ERR_PACKET);
die("git upload-pack: protocol error, "
"expected to get oid, not '%s'", line);
- o = parse_object(the_repository, &oid);
+ o = parse_object_with_flags(the_repository, &oid,
+ PARSE_OBJECT_SKIP_HASH_CHECK);
+
if (!o) {
packet_writer_error(writer,
"upload-pack: not our ref %s",
static int parse_want_ref(struct packet_writer *writer, const char *line,
struct string_list *wanted_refs,
+ struct string_list *hidden_refs,
struct object_array *want_obj)
{
const char *refname_nons;
if (skip_prefix(line, "want-ref ", &refname_nons)) {
struct object_id oid;
struct string_list_item *item;
- struct object *o;
+ struct object *o = NULL;
struct strbuf refname = STRBUF_INIT;
strbuf_addf(&refname, "%s%s", get_git_namespace(), refname_nons);
- if (ref_is_hidden(refname_nons, refname.buf) ||
+ if (ref_is_hidden(refname_nons, refname.buf, hidden_refs) ||
read_ref(refname.buf, &oid)) {
packet_writer_error(writer, "unknown ref %s", refname_nons);
die("unknown ref %s", refname_nons);
item = string_list_append(wanted_refs, refname_nons);
item->util = oiddup(&oid);
- o = parse_object_or_die(&oid, refname_nons);
+ if (!starts_with(refname_nons, "refs/tags/")) {
+ struct commit *commit = lookup_commit_in_graph(the_repository, &oid);
+ if (commit)
+ o = &commit->object;
+ }
+
+ if (!o)
+ o = parse_object_or_die(&oid, refname_nons);
+
if (!(o->flags & WANTED)) {
o->flags |= WANTED;
add_object_array(o, NULL, want_obj);
continue;
if (data->allow_ref_in_want &&
parse_want_ref(&data->writer, arg, &data->wanted_refs,
- &data->want_obj))
+ &data->hidden_refs, &data->want_obj))
continue;
/* process have line */
if (parse_have(arg, &data->haves))
FETCH_DONE,
};
-int upload_pack_v2(struct repository *r, struct strvec *keys,
- struct packet_reader *request)
+int upload_pack_v2(struct repository *r UNUSED, struct packet_reader *request)
{
enum fetch_state state = FETCH_PROCESS_ARGS;
struct upload_pack_data data;
upload_pack_data_init(&data);
data.use_sideband = LARGE_PACKET_MAX;
-
- git_config(upload_pack_config, &data);
+ get_upload_pack_config(&data);
while (state != FETCH_DONE) {
switch (state) {
strbuf_addstr(value, "shallow wait-for-done");
- if (!repo_config_get_bool(the_repository,
+ if (!repo_config_get_bool(r,
"uploadpack.allowfilter",
&allow_filter_value) &&
allow_filter_value)
strbuf_addstr(value, " filter");
- if (!repo_config_get_bool(the_repository,
+ if (!repo_config_get_bool(r,
"uploadpack.allowrefinwant",
&allow_ref_in_want) &&
allow_ref_in_want)
strbuf_addstr(value, " ref-in-want");
if (git_env_bool("GIT_TEST_SIDEBAND_ALL", 0) ||
- (!repo_config_get_bool(the_repository,
+ (!repo_config_get_bool(r,
"uploadpack.allowsidebandall",
&allow_sideband_all_value) &&
allow_sideband_all_value))
strbuf_addstr(value, " sideband-all");
- if (!repo_config_get_string(the_repository,
+ if (!repo_config_get_string(r,
"uploadpack.blobpackfileuri",
&str) &&
str) {