From: Junio C Hamano Date: Tue, 18 Oct 2011 04:37:12 +0000 (-0700) Subject: Merge branch 'tc/fetch-leak' X-Git-Tag: v1.7.8-rc0~57 X-Git-Url: https://git.lorimer.id.au/gitweb.git/diff_plain/3f7d11c45421051a010690c3b9cc28bce98b8c3f?ds=inline;hp=-c Merge branch 'tc/fetch-leak' * tc/fetch-leak: fetch: plug two leaks on error exit in store_updated_refs Conflicts: builtin/fetch.c --- 3f7d11c45421051a010690c3b9cc28bce98b8c3f diff --combined builtin/fetch.c index 7a4e41cca7,db2c5d905b..1adf6c176f --- a/builtin/fetch.c +++ b/builtin/fetch.c @@@ -13,7 -13,6 +13,7 @@@ #include "sigchain.h" #include "transport.h" #include "submodule.h" +#include "connected.h" static const char * const builtin_fetch_usage[] = { "git fetch [] [ [...]]", @@@ -346,16 -345,62 +346,16 @@@ static int update_local_ref(struct ref } } -/* - * The ref_map records the tips of the refs we are fetching. If - * - * $ git rev-list --verify-objects --stdin --not --all - * - * (feeding all the refs in ref_map on its standard input) does not - * error out, that means everything reachable from these updated refs - * locally exists and is connected to some of our existing refs. - * - * Returns 0 if everything is connected, non-zero otherwise. - */ -static int check_everything_connected(struct ref *ref_map, int quiet) +static int iterate_ref_map(void *cb_data, unsigned char sha1[20]) { - struct child_process rev_list; - const char *argv[] = {"rev-list", "--verify-objects", - "--stdin", "--not", "--all", NULL, NULL}; - char commit[41]; - struct ref *ref; - int err = 0; - - if (!ref_map) - return 0; - - if (quiet) - argv[5] = "--quiet"; - - memset(&rev_list, 0, sizeof(rev_list)); - rev_list.argv = argv; - rev_list.git_cmd = 1; - rev_list.in = -1; - rev_list.no_stdout = 1; - rev_list.no_stderr = quiet; - if (start_command(&rev_list)) - return error(_("Could not run 'git rev-list'")); - - sigchain_push(SIGPIPE, SIG_IGN); - - memcpy(commit + 40, "\n", 2); - for (ref = ref_map; ref; ref = ref->next) { - memcpy(commit, sha1_to_hex(ref->old_sha1), 40); - if (write_in_full(rev_list.in, commit, 41) < 0) { - if (errno != EPIPE && errno != EINVAL) - error(_("failed write to rev-list: %s"), - strerror(errno)); - err = -1; - break; - } - } - if (close(rev_list.in)) { - error(_("failed to close rev-list's stdin: %s"), strerror(errno)); - err = -1; - } - - sigchain_pop(SIGPIPE); + struct ref **rm = cb_data; + struct ref *ref = *rm; - return finish_command(&rev_list) || err; + if (!ref) + return -1; /* end of the list */ + *rm = ref->next; + hashcpy(sha1, ref->old_sha1); + return 0; } static int store_updated_refs(const char *raw_url, const char *remote_name, @@@ -378,9 -423,10 +378,11 @@@ else url = xstrdup("foreign"); - if (check_everything_connected(ref_map, 0)) { + rm = ref_map; - if (check_everything_connected(iterate_ref_map, 0, &rm)) - return error(_("%s did not send all necessary objects\n"), url); ++ if (check_everything_connected(iterate_ref_map, 0, &rm)) { + rc = error(_("%s did not send all necessary objects\n"), url); + goto abort; + } for (rm = ref_map; rm; rm = rm->next) { struct ref *ref = NULL; @@@ -462,12 -508,15 +464,15 @@@ fprintf(stderr, " %s\n", note); } } - free(url); - fclose(fp); + if (rc & STORE_REF_ERROR_DF_CONFLICT) error(_("some local refs could not be updated; try running\n" " 'git remote prune %s' to remove any old, conflicting " "branches"), remote_name); + + abort: + free(url); + fclose(fp); return rc; } @@@ -478,8 -527,6 +483,8 @@@ */ static int quickfetch(struct ref *ref_map) { + struct ref *rm = ref_map; + /* * If we are deepening a shallow clone we already have these * objects reachable. Running rev-list here will return with @@@ -489,7 -536,7 +494,7 @@@ */ if (depth) return -1; - return check_everything_connected(ref_map, 1); + return check_everything_connected(iterate_ref_map, 1, &rm); } static int fetch_refs(struct transport *transport, struct ref *ref_map) @@@ -840,7 -887,6 +845,7 @@@ static int fetch_one(struct remote *rem { int i; static const char **refs = NULL; + struct refspec *refspec; int ref_nr = 0; int exit_code; @@@ -881,9 -927,8 +886,9 @@@ sigchain_push_common(unlock_pack_on_signal); atexit(unlock_pack); - exit_code = do_fetch(transport, - parse_fetch_refspec(ref_nr, refs), ref_nr); + refspec = parse_fetch_refspec(ref_nr, refs); + exit_code = do_fetch(transport, refspec, ref_nr); + free(refspec); transport_disconnect(transport); transport = NULL; return exit_code; @@@ -906,15 -951,6 +911,15 @@@ int cmd_fetch(int argc, const char **ar argc = parse_options(argc, argv, prefix, builtin_fetch_options, builtin_fetch_usage, 0); + if (recurse_submodules != RECURSE_SUBMODULES_OFF) { + if (recurse_submodules_default) { + int arg = parse_fetch_recurse_submodules_arg("--recurse-submodules-default", recurse_submodules_default); + set_config_fetch_recurse_submodules(arg); + } + gitmodules_config(); + git_config(submodule_config, NULL); + } + if (all) { if (argc == 1) die(_("fetch --all does not take a repository argument")); @@@ -950,6 -986,12 +955,6 @@@ if (!result && (recurse_submodules != RECURSE_SUBMODULES_OFF)) { const char *options[10]; int num_options = 0; - if (recurse_submodules_default) { - int arg = parse_fetch_recurse_submodules_arg("--recurse-submodules-default", recurse_submodules_default); - set_config_fetch_recurse_submodules(arg); - } - gitmodules_config(); - git_config(submodule_config, NULL); add_options_to_argv(&num_options, options); result = fetch_populated_submodules(num_options, options, submodule_prefix,