diff --git a/Documentation/RelNotes/2.47.0.txt b/Documentation/RelNotes/2.47.0.txt index 6100871ec50620..e13c37f5dd7a1c 100644 --- a/Documentation/RelNotes/2.47.0.txt +++ b/Documentation/RelNotes/2.47.0.txt @@ -159,6 +159,14 @@ Performance, Internal Implementation, Development Support etc. * CI updates. FreeBSD image has been updated to 13.4. (merge 2eeb29702e cb/ci-freebsd-13-4 later to maint). + * Give timeout to the locking code to write to reftable, instead of + failing on the first failure without retrying. + + * The checksum at the tail of files are now computed without + collision detection protection. This is safe as the consumer of + the information to protect itself from replay attacks checks for + hash collisions independently. + Fixes since v2.46 ----------------- @@ -293,6 +301,33 @@ Fixes since v2.46 been corrected. (merge 9a41735af6 rs/diff-exit-code-binary later to maint). + * When a subprocess to work in a submodule spawned by "git submodule" + fails with SIGPIPE, the parent Git process caught the death of it, + but gave a generic "failed to work in that submodule", which was + misleading. We now behave as if the parent got SIGPIPE and die. + (merge 082caf527e pw/submodule-process-sigpipe later to maint). + + * "git archive" with pathspec magic that uses the attribute + information did not work well, which has been corrected. + (merge 296743a7ca rs/archive-with-attr-pathspec-fix later to maint). + + * Background tasks "git maintenance" runs may need to use credential + information when going over the network, but a credential helper + may work only in an interactive environment, and end up blocking a + scheduled task waiting for UI. Credential helpers can now behave + differently when they are not running interactively. + (merge b9183b0a02 ds/background-maintenance-with-credential later to maint). + + * "git --git-dir=nowhere cmd" failed to properly notice that it + wasn't in any repository while processing includeIf.onbranch + configuration and instead crashed. + + * When "git sparse-checkout disable" turns a sparse checkout into a + regular checkout, the index is fully expanded. This totally + expected behaviour however had an "oops, we are expanding the + index" advice message, which has been corrected. + (merge 537e516a39 ds/sparse-checkout-expansion-advice later to maint). + * Other code cleanup, docfix, build fix, etc. (merge be10ac7037 jc/mailinfo-header-cleanup later to maint). (merge 4460e052e0 jc/range-diff-lazy-setup later to maint). diff --git a/Documentation/config/credential.txt b/Documentation/config/credential.txt index 0221c3e620da89..470482ff4c2a38 100644 --- a/Documentation/config/credential.txt +++ b/Documentation/config/credential.txt @@ -9,6 +9,14 @@ credential.helper:: Note that multiple helpers may be defined. See linkgit:gitcredentials[7] for details and examples. +credential.interactive:: + By default, Git and any configured credential helpers will ask for + user input when new credentials are required. Many of these helpers + will succeed based on stored credentials if those credentials are + still valid. To avoid the possibility of user interactivity from + Git, set `credential.interactive=false`. Some credential helpers + respect this option as well. + credential.useHttpPath:: When acquiring credentials, consider the "path" component of an http or https URL to be important. Defaults to false. See diff --git a/Documentation/config/reftable.txt b/Documentation/config/reftable.txt index 05157279778339..57087803a54c06 100644 --- a/Documentation/config/reftable.txt +++ b/Documentation/config/reftable.txt @@ -46,3 +46,11 @@ reftable.geometricFactor:: By default, the geometric sequence uses a factor of 2, meaning that for any table, the next-biggest table must at least be twice as big. A maximum factor of 256 is supported. + +reftable.lockTimeout:: + Whenever the reftable backend appends a new table to the stack, it has + to lock the central "tables.list" file before updating it. This config + controls how long the process will wait to acquire the lock in case + another process has already acquired it. Value 0 means not to retry at + all; -1 means to try indefinitely. Default is 100 (i.e., retry for + 100ms). diff --git a/GIT-VERSION-GEN b/GIT-VERSION-GEN index 38e920725c5f43..1499ae59f6accb 100755 --- a/GIT-VERSION-GEN +++ b/GIT-VERSION-GEN @@ -1,7 +1,7 @@ #!/bin/sh GVF=GIT-VERSION-FILE -DEF_VER=v2.47.0-rc0 +DEF_VER=v2.47.0-rc1 LF=' ' diff --git a/Makefile b/Makefile index 778a3d2f7cbdda..aea9b14eb8b079 100644 --- a/Makefile +++ b/Makefile @@ -526,6 +526,10 @@ include shared.mak # Define APPLE_COMMON_CRYPTO_SHA1 to use Apple's CommonCrypto for # SHA-1. # +# Define the same Makefile knobs as above, but suffixed with _UNSAFE to +# use the corresponding implementations for unsafe SHA-1 hashing for +# non-cryptographic purposes. +# # If don't enable any of the *_SHA1 settings in this section, Git will # default to its built-in sha1collisiondetection library, which is a # collision-detecting sha1 This is slower, but may detect attempted @@ -2022,6 +2026,27 @@ endif endif endif +ifdef OPENSSL_SHA1_UNSAFE +ifndef OPENSSL_SHA1 + EXTLIBS += $(LIB_4_CRYPTO) + BASIC_CFLAGS += -DSHA1_OPENSSL_UNSAFE +endif +else +ifdef BLK_SHA1_UNSAFE +ifndef BLK_SHA1 + LIB_OBJS += block-sha1/sha1.o + BASIC_CFLAGS += -DSHA1_BLK_UNSAFE +endif +else +ifdef APPLE_COMMON_CRYPTO_SHA1_UNSAFE +ifndef APPLE_COMMON_CRYPTO_SHA1 + COMPAT_CFLAGS += -DCOMMON_DIGEST_FOR_OPENSSL + BASIC_CFLAGS += -DSHA1_APPLE_UNSAFE +endif +endif +endif +endif + ifdef OPENSSL_SHA256 EXTLIBS += $(LIB_4_CRYPTO) BASIC_CFLAGS += -DSHA256_OPENSSL diff --git a/archive.c b/archive.c index 9ba96aae4f742d..58f86bf75cdc7c 100644 --- a/archive.c +++ b/archive.c @@ -304,8 +304,6 @@ int write_archive_entries(struct archiver_args *args, write_archive_entry_fn_t write_entry) { struct archiver_context context; - struct unpack_trees_options opts; - struct tree_desc t; int err; struct strbuf path_in_archive = STRBUF_INIT; struct strbuf content = STRBUF_INIT; @@ -331,23 +329,6 @@ int write_archive_entries(struct archiver_args *args, context.args = args; context.write_entry = write_entry; - /* - * Setup index and instruct attr to read index only - */ - if (!args->worktree_attributes) { - memset(&opts, 0, sizeof(opts)); - opts.index_only = 1; - opts.head_idx = -1; - opts.src_index = args->repo->index; - opts.dst_index = args->repo->index; - opts.fn = oneway_merge; - init_tree_desc(&t, &args->tree->object.oid, - args->tree->buffer, args->tree->size); - if (unpack_trees(1, &t, &opts)) - return -1; - git_attr_set_direction(GIT_ATTR_INDEX); - } - err = read_tree(args->repo, args->tree, &args->pathspec, queue_or_write_archive_entry, @@ -540,6 +521,26 @@ static void parse_treeish_arg(const char **argv, if (!tree) die(_("not a tree object: %s"), oid_to_hex(&oid)); + /* + * Setup index and instruct attr to read index only + */ + if (!ar_args->worktree_attributes) { + struct unpack_trees_options opts; + struct tree_desc t; + + memset(&opts, 0, sizeof(opts)); + opts.index_only = 1; + opts.head_idx = -1; + opts.src_index = ar_args->repo->index; + opts.dst_index = ar_args->repo->index; + opts.fn = oneway_merge; + init_tree_desc(&t, &tree->object.oid, tree->buffer, tree->size); + if (unpack_trees(1, &t, &opts)) + die(_("unable to checkout working tree")); + + git_attr_set_direction(GIT_ATTR_INDEX); + } + ar_args->refname = ref; ar_args->tree = tree; ar_args->commit_oid = commit_oid; diff --git a/block-sha1/sha1.h b/block-sha1/sha1.h index 9fb0441b98849e..47bb9166368a70 100644 --- a/block-sha1/sha1.h +++ b/block-sha1/sha1.h @@ -16,7 +16,9 @@ void blk_SHA1_Init(blk_SHA_CTX *ctx); void blk_SHA1_Update(blk_SHA_CTX *ctx, const void *dataIn, size_t len); void blk_SHA1_Final(unsigned char hashout[20], blk_SHA_CTX *ctx); +#ifndef platform_SHA_CTX #define platform_SHA_CTX blk_SHA_CTX #define platform_SHA1_Init blk_SHA1_Init #define platform_SHA1_Update blk_SHA1_Update #define platform_SHA1_Final blk_SHA1_Final +#endif diff --git a/builtin/difftool.c b/builtin/difftool.c index ab93c16f1aa125..a2c0d454cc9f63 100644 --- a/builtin/difftool.c +++ b/builtin/difftool.c @@ -662,6 +662,12 @@ static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix, if (fp) fclose(fp); + hashmap_clear_and_free(&working_tree_dups, struct working_tree_entry, entry); + hashmap_clear_and_free(&wt_modified, struct path_entry, entry); + hashmap_clear_and_free(&tmp_modified, struct path_entry, entry); + hashmap_clear_and_free(&submodules, struct pair_entry, entry); + hashmap_clear_and_free(&symlinks2, struct pair_entry, entry); + release_index(&wtindex); free(lbase_dir); free(rbase_dir); strbuf_release(&info); diff --git a/builtin/fetch-pack.c b/builtin/fetch-pack.c index 49222a36fa6f29..62e8c3aa6b8e8b 100644 --- a/builtin/fetch-pack.c +++ b/builtin/fetch-pack.c @@ -53,6 +53,7 @@ int cmd_fetch_pack(int argc, struct ref *fetched_refs = NULL, *remote_refs = NULL; const char *dest = NULL; struct ref **sought = NULL; + struct ref **sought_to_free = NULL; int nr_sought = 0, alloc_sought = 0; int fd[2]; struct string_list pack_lockfiles = STRING_LIST_INIT_DUP; @@ -243,6 +244,13 @@ int cmd_fetch_pack(int argc, BUG("unknown protocol version"); } + /* + * Create a shallow copy of `sought` so that we can free all of its entries. + * This is because `fetch_pack()` will modify the array to evict some + * entries, but won't free those. + */ + DUP_ARRAY(sought_to_free, sought, nr_sought); + fetched_refs = fetch_pack(&args, fd, remote_refs, sought, nr_sought, &shallow, pack_lockfiles_ptr, version); @@ -280,9 +288,13 @@ int cmd_fetch_pack(int argc, oid_to_hex(&ref->old_oid), ref->name); for (size_t i = 0; i < nr_sought; i++) - free_one_ref(sought[i]); + free_one_ref(sought_to_free[i]); + free(sought_to_free); free(sought); free_refs(fetched_refs); free_refs(remote_refs); + list_objects_filter_release(&args.filter_options); + oid_array_clear(&shallow); + string_list_clear(&pack_lockfiles, 0); return ret; } diff --git a/builtin/fetch.c b/builtin/fetch.c index c900f577219109..80a64d0d269ed6 100644 --- a/builtin/fetch.c +++ b/builtin/fetch.c @@ -456,6 +456,7 @@ static void filter_prefetch_refspec(struct refspec *rs) free(rs->items[i].src); free(rs->items[i].dst); + free(rs->raw[i]); for (j = i + 1; j < rs->nr; j++) { rs->items[j - 1] = rs->items[j]; diff --git a/builtin/gc.c b/builtin/gc.c index c3894fb6bd163e..6a7a2da006eeee 100644 --- a/builtin/gc.c +++ b/builtin/gc.c @@ -1478,9 +1478,9 @@ static int maintenance_run_tasks(struct maintenance_run_opts *opts, static void initialize_maintenance_strategy(void) { - char *config_str; + const char *config_str; - if (git_config_get_string("maintenance.strategy", &config_str)) + if (git_config_get_string_tmp("maintenance.strategy", &config_str)) return; if (!strcasecmp(config_str, "incremental")) { @@ -1768,6 +1768,42 @@ static const char *get_frequency(enum schedule_priority schedule) } } +static const char *extraconfig[] = { + "credential.interactive=false", + "core.askPass=true", /* 'true' returns success, but no output. */ + NULL +}; + +static const char *get_extra_config_parameters(void) { + static const char *result = NULL; + struct strbuf builder = STRBUF_INIT; + + if (result) + return result; + + for (const char **s = extraconfig; s && *s; s++) + strbuf_addf(&builder, "-c %s ", *s); + + result = strbuf_detach(&builder, NULL); + return result; +} + +static const char *get_extra_launchctl_strings(void) { + static const char *result = NULL; + struct strbuf builder = STRBUF_INIT; + + if (result) + return result; + + for (const char **s = extraconfig; s && *s; s++) { + strbuf_addstr(&builder, "-c\n"); + strbuf_addf(&builder, "%s\n", *s); + } + + result = strbuf_detach(&builder, NULL); + return result; +} + /* * get_schedule_cmd` reads the GIT_TEST_MAINT_SCHEDULER environment variable * to mock the schedulers that `git maintenance start` rely on. @@ -1782,32 +1818,33 @@ static const char *get_frequency(enum schedule_priority schedule) * * If $GIT_TEST_MAINT_SCHEDULER is set, return true. * In this case, the *cmd value is read as input. * - * * if the input value *cmd is the key of one of the comma-separated list - * item, then *is_available is set to true and *cmd is modified and becomes + * * if the input value cmd is the key of one of the comma-separated list + * item, then *is_available is set to true and *out is set to * the mock command. * * * if the input value *cmd isn’t the key of any of the comma-separated list - * item, then *is_available is set to false. + * item, then *is_available is set to false and *out is set to the original + * command. * * Ex.: * GIT_TEST_MAINT_SCHEDULER not set * +-------+-------------------------------------------------+ * | Input | Output | - * | *cmd | return code | *cmd | *is_available | + * | *cmd | return code | *out | *is_available | * +-------+-------------+-------------------+---------------+ - * | "foo" | false | "foo" (unchanged) | (unchanged) | + * | "foo" | false | NULL | (unchanged) | * +-------+-------------+-------------------+---------------+ * * GIT_TEST_MAINT_SCHEDULER set to “foo:./mock_foo.sh,bar:./mock_bar.sh” * +-------+-------------------------------------------------+ * | Input | Output | - * | *cmd | return code | *cmd | *is_available | + * | *cmd | return code | *out | *is_available | * +-------+-------------+-------------------+---------------+ * | "foo" | true | "./mock.foo.sh" | true | - * | "qux" | true | "qux" (unchanged) | false | + * | "qux" | true | "qux" (allocated) | false | * +-------+-------------+-------------------+---------------+ */ -static int get_schedule_cmd(const char **cmd, int *is_available) +static int get_schedule_cmd(const char *cmd, int *is_available, char **out) { char *testing = xstrdup_or_null(getenv("GIT_TEST_MAINT_SCHEDULER")); struct string_list_item *item; @@ -1826,16 +1863,22 @@ static int get_schedule_cmd(const char **cmd, int *is_available) if (string_list_split_in_place(&pair, item->string, ":", 2) != 2) continue; - if (!strcmp(*cmd, pair.items[0].string)) { - *cmd = pair.items[1].string; + if (!strcmp(cmd, pair.items[0].string)) { + if (out) + *out = xstrdup(pair.items[1].string); if (is_available) *is_available = 1; - string_list_clear(&list, 0); - UNLEAK(testing); - return 1; + string_list_clear(&pair, 0); + goto out; } + + string_list_clear(&pair, 0); } + if (out) + *out = xstrdup(cmd); + +out: string_list_clear(&list, 0); free(testing); return 1; @@ -1852,9 +1895,8 @@ static int get_random_minute(void) static int is_launchctl_available(void) { - const char *cmd = "launchctl"; int is_available; - if (get_schedule_cmd(&cmd, &is_available)) + if (get_schedule_cmd("launchctl", &is_available, NULL)) return is_available; #ifdef __APPLE__ @@ -1892,12 +1934,12 @@ static char *launchctl_get_uid(void) static int launchctl_boot_plist(int enable, const char *filename) { - const char *cmd = "launchctl"; + char *cmd; int result; struct child_process child = CHILD_PROCESS_INIT; char *uid = launchctl_get_uid(); - get_schedule_cmd(&cmd, NULL); + get_schedule_cmd("launchctl", NULL, &cmd); strvec_split(&child.args, cmd); strvec_pushl(&child.args, enable ? "bootstrap" : "bootout", uid, filename, NULL); @@ -1910,6 +1952,7 @@ static int launchctl_boot_plist(int enable, const char *filename) result = finish_command(&child); + free(cmd); free(uid); return result; } @@ -1961,10 +2004,10 @@ static int launchctl_schedule_plist(const char *exec_path, enum schedule_priorit static unsigned long lock_file_timeout_ms = ULONG_MAX; struct strbuf plist = STRBUF_INIT, plist2 = STRBUF_INIT; struct stat st; - const char *cmd = "launchctl"; + char *cmd; int minute = get_random_minute(); - get_schedule_cmd(&cmd, NULL); + get_schedule_cmd("launchctl", NULL, &cmd); preamble = "\n" "\n" "" @@ -1974,6 +2017,7 @@ static int launchctl_schedule_plist(const char *exec_path, enum schedule_priorit "\n" "%s/git\n" "--exec-path=%s\n" + "%s" /* For extra config parameters. */ "for-each-repo\n" "--keep-going\n" "--config=maintenance.repo\n" @@ -1983,7 +2027,8 @@ static int launchctl_schedule_plist(const char *exec_path, enum schedule_priorit "\n" "StartCalendarInterval\n" "\n"; - strbuf_addf(&plist, preamble, name, exec_path, exec_path, frequency); + strbuf_addf(&plist, preamble, name, exec_path, exec_path, + get_extra_launchctl_strings(), frequency); switch (schedule) { case SCHEDULE_HOURLY: @@ -2054,6 +2099,7 @@ static int launchctl_schedule_plist(const char *exec_path, enum schedule_priorit free(filename); free(name); + free(cmd); strbuf_release(&plist); strbuf_release(&plist2); return 0; @@ -2078,9 +2124,8 @@ static int launchctl_update_schedule(int run_maintenance, int fd UNUSED) static int is_schtasks_available(void) { - const char *cmd = "schtasks"; int is_available; - if (get_schedule_cmd(&cmd, &is_available)) + if (get_schedule_cmd("schtasks", &is_available, NULL)) return is_available; #ifdef GIT_WINDOWS_NATIVE @@ -2099,15 +2144,16 @@ static char *schtasks_task_name(const char *frequency) static int schtasks_remove_task(enum schedule_priority schedule) { - const char *cmd = "schtasks"; + char *cmd; struct child_process child = CHILD_PROCESS_INIT; const char *frequency = get_frequency(schedule); char *name = schtasks_task_name(frequency); - get_schedule_cmd(&cmd, NULL); + get_schedule_cmd("schtasks", NULL, &cmd); strvec_split(&child.args, cmd); strvec_pushl(&child.args, "/delete", "/tn", name, "/f", NULL); free(name); + free(cmd); return run_command(&child); } @@ -2121,7 +2167,7 @@ static int schtasks_remove_tasks(void) static int schtasks_schedule_task(const char *exec_path, enum schedule_priority schedule) { - const char *cmd = "schtasks"; + char *cmd; int result; struct child_process child = CHILD_PROCESS_INIT; const char *xml; @@ -2131,7 +2177,7 @@ static int schtasks_schedule_task(const char *exec_path, enum schedule_priority struct strbuf tfilename = STRBUF_INIT; int minute = get_random_minute(); - get_schedule_cmd(&cmd, NULL); + get_schedule_cmd("schtasks", NULL, &cmd); strbuf_addf(&tfilename, "%s/schedule_%s_XXXXXX", repo_get_common_dir(the_repository), frequency); @@ -2218,11 +2264,12 @@ static int schtasks_schedule_task(const char *exec_path, enum schedule_priority "\n" "\n" "\"%s\\headless-git.exe\"\n" - "--exec-path=\"%s\" for-each-repo --keep-going --config=maintenance.repo maintenance run --schedule=%s\n" + "--exec-path=\"%s\" %s for-each-repo --keep-going --config=maintenance.repo maintenance run --schedule=%s\n" "\n" "\n" "\n"; - fprintf(tfile->fp, xml, exec_path, exec_path, frequency); + fprintf(tfile->fp, xml, exec_path, exec_path, + get_extra_config_parameters(), frequency); strvec_split(&child.args, cmd); strvec_pushl(&child.args, "/create", "/tn", name, "/f", "/xml", get_tempfile_path(tfile), NULL); @@ -2237,6 +2284,7 @@ static int schtasks_schedule_task(const char *exec_path, enum schedule_priority delete_tempfile(&tfile); free(name); + free(cmd); return result; } @@ -2278,21 +2326,28 @@ static int check_crontab_process(const char *cmd) static int is_crontab_available(void) { - const char *cmd = "crontab"; + char *cmd; int is_available; + int ret; - if (get_schedule_cmd(&cmd, &is_available)) - return is_available; + if (get_schedule_cmd("crontab", &is_available, &cmd)) { + ret = is_available; + goto out; + } #ifdef __APPLE__ /* * macOS has cron, but it requires special permissions and will * create a UI alert when attempting to run this command. */ - return 0; + ret = 0; #else - return check_crontab_process(cmd); + ret = check_crontab_process(cmd); #endif + +out: + free(cmd); + return ret; } #define BEGIN_LINE "# BEGIN GIT MAINTENANCE SCHEDULE" @@ -2300,7 +2355,7 @@ static int is_crontab_available(void) static int crontab_update_schedule(int run_maintenance, int fd) { - const char *cmd = "crontab"; + char *cmd; int result = 0; int in_old_region = 0; struct child_process crontab_list = CHILD_PROCESS_INIT; @@ -2310,15 +2365,17 @@ static int crontab_update_schedule(int run_maintenance, int fd) struct tempfile *tmpedit = NULL; int minute = get_random_minute(); - get_schedule_cmd(&cmd, NULL); + get_schedule_cmd("crontab", NULL, &cmd); strvec_split(&crontab_list.args, cmd); strvec_push(&crontab_list.args, "-l"); crontab_list.in = -1; crontab_list.out = dup(fd); crontab_list.git_cmd = 0; - if (start_command(&crontab_list)) - return error(_("failed to run 'crontab -l'; your system might not support 'cron'")); + if (start_command(&crontab_list)) { + result = error(_("failed to run 'crontab -l'; your system might not support 'cron'")); + goto out; + } /* Ignore exit code, as an empty crontab will return error. */ finish_command(&crontab_list); @@ -2363,8 +2420,8 @@ static int crontab_update_schedule(int run_maintenance, int fd) "# replaced in the future by a Git command.\n\n"); strbuf_addf(&line_format, - "%%d %%s * * %%s \"%s/git\" --exec-path=\"%s\" for-each-repo --keep-going --config=maintenance.repo maintenance run --schedule=%%s\n", - exec_path, exec_path); + "%%d %%s * * %%s \"%s/git\" --exec-path=\"%s\" %s for-each-repo --keep-going --config=maintenance.repo maintenance run --schedule=%%s\n", + exec_path, exec_path, get_extra_config_parameters()); fprintf(cron_in, line_format.buf, minute, "1-23", "*", "hourly"); fprintf(cron_in, line_format.buf, minute, "0", "1-6", "daily"); fprintf(cron_in, line_format.buf, minute, "0", "0", "weekly"); @@ -2388,8 +2445,10 @@ static int crontab_update_schedule(int run_maintenance, int fd) result = error(_("'crontab' died")); else fclose(cron_list); + out: delete_tempfile(&tmpedit); + free(cmd); return result; } @@ -2412,10 +2471,9 @@ static int real_is_systemd_timer_available(void) static int is_systemd_timer_available(void) { - const char *cmd = "systemctl"; int is_available; - if (get_schedule_cmd(&cmd, &is_available)) + if (get_schedule_cmd("systemctl", &is_available, NULL)) return is_available; return real_is_systemd_timer_available(); @@ -2564,7 +2622,7 @@ static int systemd_timer_write_service_template(const char *exec_path) "\n" "[Service]\n" "Type=oneshot\n" - "ExecStart=\"%s/git\" --exec-path=\"%s\" for-each-repo --keep-going --config=maintenance.repo maintenance run --schedule=%%i\n" + "ExecStart=\"%s/git\" --exec-path=\"%s\" %s for-each-repo --keep-going --config=maintenance.repo maintenance run --schedule=%%i\n" "LockPersonality=yes\n" "MemoryDenyWriteExecute=yes\n" "NoNewPrivileges=yes\n" @@ -2574,7 +2632,7 @@ static int systemd_timer_write_service_template(const char *exec_path) "RestrictSUIDSGID=yes\n" "SystemCallArchitectures=native\n" "SystemCallFilter=@system-service\n"; - if (fprintf(file, unit, exec_path, exec_path) < 0) { + if (fprintf(file, unit, exec_path, exec_path, get_extra_config_parameters()) < 0) { error(_("failed to write to '%s'"), filename); fclose(file); goto error; @@ -2596,9 +2654,10 @@ static int systemd_timer_enable_unit(int enable, enum schedule_priority schedule, int minute) { - const char *cmd = "systemctl"; + char *cmd = NULL; struct child_process child = CHILD_PROCESS_INIT; const char *frequency = get_frequency(schedule); + int ret; /* * Disabling the systemd unit while it is already disabled makes @@ -2609,20 +2668,25 @@ static int systemd_timer_enable_unit(int enable, * On the other hand, enabling a systemd unit which is already enabled * produces no error. */ - if (!enable) + if (!enable) { child.no_stderr = 1; - else if (systemd_timer_write_timer_file(schedule, minute)) - return -1; + } else if (systemd_timer_write_timer_file(schedule, minute)) { + ret = -1; + goto out; + } - get_schedule_cmd(&cmd, NULL); + get_schedule_cmd("systemctl", NULL, &cmd); strvec_split(&child.args, cmd); strvec_pushl(&child.args, "--user", enable ? "enable" : "disable", "--now", NULL); strvec_pushf(&child.args, SYSTEMD_UNIT_FORMAT, frequency, "timer"); - if (start_command(&child)) - return error(_("failed to start systemctl")); - if (finish_command(&child)) + if (start_command(&child)) { + ret = error(_("failed to start systemctl")); + goto out; + } + + if (finish_command(&child)) { /* * Disabling an already disabled systemd unit makes * systemctl fail. @@ -2630,9 +2694,17 @@ static int systemd_timer_enable_unit(int enable, * * Enabling an enabled systemd unit doesn't fail. */ - if (enable) - return error(_("failed to run systemctl")); - return 0; + if (enable) { + ret = error(_("failed to run systemctl")); + goto out; + } + } + + ret = 0; + +out: + free(cmd); + return ret; } /* diff --git a/builtin/help.c b/builtin/help.c index a509241a80fc0c..4a5a0790704b40 100644 --- a/builtin/help.c +++ b/builtin/help.c @@ -54,7 +54,7 @@ static enum help_action { HELP_ACTION_CONFIG_SECTIONS_FOR_COMPLETION, } cmd_mode; -static const char *html_path; +static char *html_path; static int verbose = 1; static enum help_format help_format = HELP_FORMAT_NONE; static int exclude_guides; @@ -411,6 +411,7 @@ static int git_help_config(const char *var, const char *value, if (!strcmp(var, "help.htmlpath")) { if (!value) return config_error_nonbool(var); + free(html_path); html_path = xstrdup(value); return 0; } @@ -515,23 +516,24 @@ static void show_info_page(const char *page) static void get_html_page_path(struct strbuf *page_path, const char *page) { struct stat st; + const char *path = html_path; char *to_free = NULL; - if (!html_path) - html_path = to_free = system_path(GIT_HTML_PATH); + if (!path) + path = to_free = system_path(GIT_HTML_PATH); /* * Check that the page we're looking for exists. */ - if (!strstr(html_path, "://")) { - if (stat(mkpath("%s/%s.html", html_path, page), &st) + if (!strstr(path, "://")) { + if (stat(mkpath("%s/%s.html", path, page), &st) || !S_ISREG(st.st_mode)) die("'%s/%s.html': documentation file not found.", - html_path, page); + path, page); } strbuf_init(page_path, 0); - strbuf_addf(page_path, "%s/%s.html", html_path, page); + strbuf_addf(page_path, "%s/%s.html", path, page); free(to_free); } diff --git a/builtin/pull.c b/builtin/pull.c index 149f201320549f..388ef3d1306bef 100644 --- a/builtin/pull.c +++ b/builtin/pull.c @@ -85,7 +85,7 @@ static const char *opt_squash; static const char *opt_commit; static const char *opt_edit; static const char *cleanup_arg; -static const char *opt_ff; +static char *opt_ff; static const char *opt_verify_signatures; static const char *opt_verify; static int opt_autostash = -1; @@ -1028,8 +1028,10 @@ int cmd_pull(int argc, * "--rebase" can override a config setting of * pull.ff=only. */ - if (opt_rebase >= 0 && opt_ff && !strcmp(opt_ff, "--ff-only")) - opt_ff = "--ff"; + if (opt_rebase >= 0 && opt_ff && !strcmp(opt_ff, "--ff-only")) { + free(opt_ff); + opt_ff = xstrdup("--ff"); + } } if (opt_rebase < 0) @@ -1139,7 +1141,8 @@ int cmd_pull(int argc, if (can_ff) { /* we can fast-forward this without invoking rebase */ - opt_ff = "--ff-only"; + free(opt_ff); + opt_ff = xstrdup("--ff-only"); ret = run_merge(); } else { ret = run_rebase(&newbase, &upstream); diff --git a/builtin/push.c b/builtin/push.c index e6f48969b81a06..59d4485603a386 100644 --- a/builtin/push.c +++ b/builtin/push.c @@ -669,6 +669,7 @@ int cmd_push(int argc, rc = do_push(flags, push_options, remote); string_list_clear(&push_options_cmdline, 0); string_list_clear(&push_options_config, 0); + clear_cas_option(&cas); if (rc == -1) usage_with_options(push_usage, options); else diff --git a/builtin/repack.c b/builtin/repack.c index a994b48f08dfc0..2b6ecb7c8020f9 100644 --- a/builtin/repack.c +++ b/builtin/repack.c @@ -90,17 +90,34 @@ static int repack_config(const char *var, const char *value, run_update_server_info = git_config_bool(var, value); return 0; } - if (!strcmp(var, "repack.cruftwindow")) + if (!strcmp(var, "repack.cruftwindow")) { + free(cruft_po_args->window); return git_config_string(&cruft_po_args->window, var, value); - if (!strcmp(var, "repack.cruftwindowmemory")) + } + if (!strcmp(var, "repack.cruftwindowmemory")) { + free(cruft_po_args->window_memory); return git_config_string(&cruft_po_args->window_memory, var, value); - if (!strcmp(var, "repack.cruftdepth")) + } + if (!strcmp(var, "repack.cruftdepth")) { + free(cruft_po_args->depth); return git_config_string(&cruft_po_args->depth, var, value); - if (!strcmp(var, "repack.cruftthreads")) + } + if (!strcmp(var, "repack.cruftthreads")) { + free(cruft_po_args->threads); return git_config_string(&cruft_po_args->threads, var, value); + } return git_default_config(var, value, ctx, cb); } +static void pack_objects_args_release(struct pack_objects_args *args) +{ + free(args->window); + free(args->window_memory); + free(args->depth); + free(args->threads); + list_objects_filter_release(&args->filter_options); +} + struct existing_packs { struct string_list kept_packs; struct string_list non_kept_packs; @@ -1164,12 +1181,16 @@ int cmd_repack(int argc, const char *unpack_unreachable = NULL; int keep_unreachable = 0; struct string_list keep_pack_list = STRING_LIST_INIT_NODUP; - struct pack_objects_args po_args = {NULL}; - struct pack_objects_args cruft_po_args = {NULL}; + struct pack_objects_args po_args = { 0 }; + struct pack_objects_args cruft_po_args = { 0 }; int write_midx = 0; const char *cruft_expiration = NULL; const char *expire_to = NULL; const char *filter_to = NULL; + const char *opt_window = NULL; + const char *opt_window_memory = NULL; + const char *opt_depth = NULL; + const char *opt_threads = NULL; struct option builtin_repack_options[] = { OPT_BIT('a', NULL, &pack_everything, @@ -1207,13 +1228,13 @@ int cmd_repack(int argc, N_("with -A, do not loosen objects older than this")), OPT_BOOL('k', "keep-unreachable", &keep_unreachable, N_("with -a, repack unreachable objects")), - OPT_STRING(0, "window", &po_args.window, N_("n"), + OPT_STRING(0, "window", &opt_window, N_("n"), N_("size of the window used for delta compression")), - OPT_STRING(0, "window-memory", &po_args.window_memory, N_("bytes"), + OPT_STRING(0, "window-memory", &opt_window_memory, N_("bytes"), N_("same as the above, but limit memory size instead of entries count")), - OPT_STRING(0, "depth", &po_args.depth, N_("n"), + OPT_STRING(0, "depth", &opt_depth, N_("n"), N_("limits the maximum delta depth")), - OPT_STRING(0, "threads", &po_args.threads, N_("n"), + OPT_STRING(0, "threads", &opt_threads, N_("n"), N_("limits the maximum number of threads")), OPT_MAGNITUDE(0, "max-pack-size", &po_args.max_pack_size, N_("maximum size of each packfile")), @@ -1240,6 +1261,11 @@ int cmd_repack(int argc, argc = parse_options(argc, argv, prefix, builtin_repack_options, git_repack_usage, 0); + po_args.window = xstrdup_or_null(opt_window); + po_args.window_memory = xstrdup_or_null(opt_window_memory); + po_args.depth = xstrdup_or_null(opt_depth); + po_args.threads = xstrdup_or_null(opt_threads); + if (delete_redundant && repository_format_precious_objects) die(_("cannot delete packs in a precious-objects repo")); @@ -1405,13 +1431,13 @@ int cmd_repack(int argc, const char *pack_prefix = find_pack_prefix(packdir, packtmp); if (!cruft_po_args.window) - cruft_po_args.window = po_args.window; + cruft_po_args.window = xstrdup_or_null(po_args.window); if (!cruft_po_args.window_memory) - cruft_po_args.window_memory = po_args.window_memory; + cruft_po_args.window_memory = xstrdup_or_null(po_args.window_memory); if (!cruft_po_args.depth) - cruft_po_args.depth = po_args.depth; + cruft_po_args.depth = xstrdup_or_null(po_args.depth); if (!cruft_po_args.threads) - cruft_po_args.threads = po_args.threads; + cruft_po_args.threads = xstrdup_or_null(po_args.threads); if (!cruft_po_args.max_pack_size) cruft_po_args.max_pack_size = po_args.max_pack_size; @@ -1564,7 +1590,8 @@ int cmd_repack(int argc, string_list_clear(&names, 1); existing_packs_release(&existing); free_pack_geometry(&geometry); - list_objects_filter_release(&po_args.filter_options); + pack_objects_args_release(&po_args); + pack_objects_args_release(&cruft_po_args); return ret; } diff --git a/builtin/send-pack.c b/builtin/send-pack.c index 81fc96d423afd7..8b1d46e79a8724 100644 --- a/builtin/send-pack.c +++ b/builtin/send-pack.c @@ -343,5 +343,7 @@ int cmd_send_pack(int argc, free_refs(remote_refs); free_refs(local_refs); refspec_clear(&rs); + oid_array_clear(&shallow); + clear_cas_option(&cas); return ret; } diff --git a/builtin/sparse-checkout.c b/builtin/sparse-checkout.c index e4e791a4c9a6c2..49aedc1de81a17 100644 --- a/builtin/sparse-checkout.c +++ b/builtin/sparse-checkout.c @@ -924,6 +924,11 @@ static int sparse_checkout_disable(int argc, const char **argv, builtin_sparse_checkout_disable_options, builtin_sparse_checkout_disable_usage, 0); + /* + * Disable the advice message for expanding a sparse index, as we + * are expecting to do that when disabling sparse-checkout. + */ + give_advice_on_expansion = 0; repo_read_index(the_repository); memset(&pl, 0, sizeof(pl)); diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c index a1ada869523e70..dc89488a7da335 100644 --- a/builtin/submodule--helper.c +++ b/builtin/submodule--helper.c @@ -364,9 +364,13 @@ static void runcommand_in_submodule_cb(const struct cache_entry *list_item, if (!info->quiet) printf(_("Entering '%s'\n"), displaypath); - if (info->argv[0] && run_command(&cp)) - die(_("run_command returned non-zero status for %s\n."), - displaypath); + if (info->argv[0]) { + if (run_command(&cp)) + die(_("run_command returned non-zero status for %s\n."), + displaypath); + } else { + child_process_clear(&cp); + } if (info->recursive) { struct child_process cpr = CHILD_PROCESS_INIT; @@ -696,6 +700,7 @@ static void status_submodule(const char *path, const struct object_id *ce_oid, if (flags & OPT_RECURSIVE) { struct child_process cpr = CHILD_PROCESS_INIT; + int res; cpr.git_cmd = 1; cpr.dir = path; @@ -711,7 +716,10 @@ static void status_submodule(const char *path, const struct object_id *ce_oid, if (flags & OPT_QUIET) strvec_push(&cpr.args, "--quiet"); - if (run_command(&cpr)) + res = run_command(&cpr); + if (res == SIGPIPE + 128) + raise(SIGPIPE); + else if (res) die(_("failed to recurse into submodule '%s'"), path); } @@ -1618,6 +1626,8 @@ static int add_possible_reference_from_superproject( ; /* nothing */ } } + + strbuf_release(&err); strbuf_release(&sb); } @@ -2022,6 +2032,7 @@ struct update_data { static void update_data_release(struct update_data *ud) { free(ud->displaypath); + submodule_update_strategy_release(&ud->update_strategy); module_list_release(&ud->list); } @@ -2642,15 +2653,20 @@ static int update_submodule(struct update_data *update_data) if (!update_data->nofetch) { if (fetch_in_submodule(update_data->sm_path, update_data->depth, - 0, NULL)) + 0, NULL)) { + free(remote_ref); return die_message(_("Unable to fetch in submodule path '%s'"), update_data->sm_path); + } } if (repo_resolve_gitlink_ref(the_repository, update_data->sm_path, - remote_ref, &update_data->oid)) - return die_message(_("Unable to find %s revision in submodule path '%s'"), - remote_ref, update_data->sm_path); + remote_ref, &update_data->oid)) { + ret = die_message(_("Unable to find %s revision in submodule path '%s'"), + remote_ref, update_data->sm_path); + free(remote_ref); + return ret; + } free(remote_ref); } diff --git a/combine-diff.c b/combine-diff.c index 829a44e4167300..f6b624dc288d72 100644 --- a/combine-diff.c +++ b/combine-diff.c @@ -1393,9 +1393,8 @@ static struct combine_diff_path *find_paths_generic(const struct object_id *oid, { struct combine_diff_path *paths = NULL; int i, num_parent = parents->nr; - int output_format = opt->output_format; - const char *orderfile = opt->orderfile; + char *orderfile = opt->orderfile; opt->output_format = DIFF_FORMAT_NO_OUTPUT; /* tell diff_tree to emit paths in sorted (=tree) order */ diff --git a/commit-graph.c b/commit-graph.c index aa6e08eb39cd5f..5bd89c0acdd03d 100644 --- a/commit-graph.c +++ b/commit-graph.c @@ -2055,7 +2055,6 @@ static int write_commit_graph_file(struct write_commit_graph_context *ctx) } if (safe_create_leading_directories(ctx->graph_name)) { - UNLEAK(ctx->graph_name); error(_("unable to create leading directories of %s"), ctx->graph_name); return -1; diff --git a/commit.c b/commit.c index 3a54e4db0d2085..cc03a9303623ad 100644 --- a/commit.c +++ b/commit.c @@ -595,7 +595,8 @@ int repo_parse_commit_internal(struct repository *r, } ret = parse_commit_buffer(r, item, buffer, size, 0); - if (save_commit_buffer && !ret) { + if (save_commit_buffer && !ret && + !get_cached_commit_buffer(r, item, NULL)) { set_commit_buffer(r, item, buffer, size); return 0; } diff --git a/config.c b/config.c index 5d0a209801a19a..bfca0ea5fd97f5 100644 --- a/config.c +++ b/config.c @@ -306,13 +306,16 @@ static int include_by_branch(struct config_include_data *data, int flags; int ret; struct strbuf pattern = STRBUF_INIT; - const char *refname = (!data->repo || !data->repo->gitdir) ? - NULL : refs_resolve_ref_unsafe(get_main_ref_store(data->repo), - "HEAD", 0, NULL, &flags); - const char *shortname; + const char *refname, *shortname; - if (!refname || !(flags & REF_ISSYMREF) || - !skip_prefix(refname, "refs/heads/", &shortname)) + if (!data->repo || data->repo->ref_storage_format == REF_STORAGE_FORMAT_UNKNOWN) + return 0; + + refname = refs_resolve_ref_unsafe(get_main_ref_store(data->repo), + "HEAD", 0, NULL, &flags); + if (!refname || + !(flags & REF_ISSYMREF) || + !skip_prefix(refname, "refs/heads/", &shortname)) return 0; strbuf_add(&pattern, cond, cond_len); diff --git a/connect.c b/connect.c index 6829ab397455c4..58f53d8dcbb87d 100644 --- a/connect.c +++ b/connect.c @@ -1485,6 +1485,7 @@ struct child_process *git_connect(int fd[2], const char *url, free(hostandport); free(path); + child_process_clear(conn); free(conn); strbuf_release(&cmd); return NULL; diff --git a/credential.c b/credential.c index ee46351ce01510..6dea3859ece338 100644 --- a/credential.c +++ b/credential.c @@ -13,6 +13,8 @@ #include "strbuf.h" #include "urlmatch.h" #include "git-compat-util.h" +#include "trace2.h" +#include "repository.h" void credential_init(struct credential *c) { @@ -251,14 +253,36 @@ static char *credential_ask_one(const char *what, struct credential *c, return xstrdup(r); } -static void credential_getpass(struct credential *c) +static int credential_getpass(struct credential *c) { + int interactive; + char *value; + if (!git_config_get_maybe_bool("credential.interactive", &interactive) && + !interactive) { + trace2_data_intmax("credential", the_repository, + "interactive/skipped", 1); + return -1; + } + if (!git_config_get_string("credential.interactive", &value)) { + int same = !strcmp(value, "never"); + free(value); + if (same) { + trace2_data_intmax("credential", the_repository, + "interactive/skipped", 1); + return -1; + } + } + + trace2_region_enter("credential", "interactive", the_repository); if (!c->username) c->username = credential_ask_one("Username", c, PROMPT_ASKPASS|PROMPT_ECHO); if (!c->password) c->password = credential_ask_one("Password", c, PROMPT_ASKPASS); + trace2_region_leave("credential", "interactive", the_repository); + + return 0; } int credential_has_capability(const struct credential_capability *capa, @@ -501,8 +525,8 @@ void credential_fill(struct credential *c, int all_capabilities) c->helpers.items[i].string); } - credential_getpass(c); - if (!c->username && !c->password && !c->credential) + if (credential_getpass(c) || + (!c->username && !c->password && !c->credential)) die("unable to get password from user"); } diff --git a/csum-file.c b/csum-file.c index bf82ad8f9f5522..c203ebf11b3444 100644 --- a/csum-file.c +++ b/csum-file.c @@ -50,7 +50,7 @@ void hashflush(struct hashfile *f) if (offset) { if (!f->skip_hash) - the_hash_algo->update_fn(&f->ctx, f->buffer, offset); + the_hash_algo->unsafe_update_fn(&f->ctx, f->buffer, offset); flush(f, f->buffer, offset); f->offset = 0; } @@ -73,7 +73,7 @@ int finalize_hashfile(struct hashfile *f, unsigned char *result, if (f->skip_hash) hashclr(f->buffer, the_repository->hash_algo); else - the_hash_algo->final_fn(f->buffer, &f->ctx); + the_hash_algo->unsafe_final_fn(f->buffer, &f->ctx); if (result) hashcpy(result, f->buffer, the_repository->hash_algo); @@ -128,7 +128,7 @@ void hashwrite(struct hashfile *f, const void *buf, unsigned int count) * f->offset is necessarily zero. */ if (!f->skip_hash) - the_hash_algo->update_fn(&f->ctx, buf, nr); + the_hash_algo->unsafe_update_fn(&f->ctx, buf, nr); flush(f, buf, nr); } else { /* @@ -174,7 +174,7 @@ static struct hashfile *hashfd_internal(int fd, const char *name, f->name = name; f->do_crc = 0; f->skip_hash = 0; - the_hash_algo->init_fn(&f->ctx); + the_hash_algo->unsafe_init_fn(&f->ctx); f->buffer_len = buffer_len; f->buffer = xmalloc(buffer_len); @@ -208,7 +208,7 @@ void hashfile_checkpoint(struct hashfile *f, struct hashfile_checkpoint *checkpo { hashflush(f); checkpoint->offset = f->total; - the_hash_algo->clone_fn(&checkpoint->ctx, &f->ctx); + the_hash_algo->unsafe_clone_fn(&checkpoint->ctx, &f->ctx); } int hashfile_truncate(struct hashfile *f, struct hashfile_checkpoint *checkpoint) @@ -219,7 +219,7 @@ int hashfile_truncate(struct hashfile *f, struct hashfile_checkpoint *checkpoint lseek(f->fd, offset, SEEK_SET) != offset) return -1; f->total = offset; - the_hash_algo->clone_fn(&f->ctx, &checkpoint->ctx); + the_hash_algo->unsafe_clone_fn(&f->ctx, &checkpoint->ctx); f->offset = 0; /* hashflush() was called in checkpoint */ return 0; } @@ -245,9 +245,9 @@ int hashfile_checksum_valid(const unsigned char *data, size_t total_len) if (total_len < the_hash_algo->rawsz) return 0; /* say "too short"? */ - the_hash_algo->init_fn(&ctx); - the_hash_algo->update_fn(&ctx, data, data_len); - the_hash_algo->final_fn(got, &ctx); + the_hash_algo->unsafe_init_fn(&ctx); + the_hash_algo->unsafe_update_fn(&ctx, data, data_len); + the_hash_algo->unsafe_final_fn(got, &ctx); return hasheq(got, data + data_len, the_repository->hash_algo); } diff --git a/diff.c b/diff.c index 84a6bb08681e6d..173cbe2bed3501 100644 --- a/diff.c +++ b/diff.c @@ -443,8 +443,10 @@ int git_diff_ui_config(const char *var, const char *value, } if (!strcmp(var, "diff.wordregex")) return git_config_string(&diff_word_regex_cfg, var, value); - if (!strcmp(var, "diff.orderfile")) + if (!strcmp(var, "diff.orderfile")) { + FREE_AND_NULL(diff_order_file_cfg); return git_config_pathname(&diff_order_file_cfg, var, value); + } if (!strcmp(var, "diff.ignoresubmodules")) { if (!value) @@ -4778,7 +4780,7 @@ void repo_diff_setup(struct repository *r, struct diff_options *options) if (diff_indent_heuristic) DIFF_XDL_SET(options, INDENT_HEURISTIC); - options->orderfile = diff_order_file_cfg; + options->orderfile = xstrdup_or_null(diff_order_file_cfg); if (!options->flags.ignore_submodule_set) options->flags.ignore_untracked_in_submodules = 1; @@ -6730,6 +6732,7 @@ void diff_free(struct diff_options *options) FREE_AND_NULL(options->objfind); } + FREE_AND_NULL(options->orderfile); for (size_t i = 0; i < options->anchors_nr; i++) free(options->anchors[i]); FREE_AND_NULL(options->anchors); diff --git a/diff.h b/diff.h index fb40c6e6d60eb0..0cde3b34e23985 100644 --- a/diff.h +++ b/diff.h @@ -235,7 +235,7 @@ enum diff_submodule_format { * diffcore library with. */ struct diff_options { - const char *orderfile; + char *orderfile; /* * "--rotate-to=" would start showing at and when diff --git a/diffcore-break.c b/diffcore-break.c index 831b66b5c3e85c..02735f80c6582e 100644 --- a/diffcore-break.c +++ b/diffcore-break.c @@ -266,8 +266,8 @@ static void merge_broken(struct diff_filepair *p, * in the resulting tree. */ d->one->rename_used++; - diff_free_filespec_data(d->two); - diff_free_filespec_data(c->one); + free_filespec(d->two); + free_filespec(c->one); free(d); free(c); } diff --git a/diffcore-order.c b/diffcore-order.c index e7d20ebd2d1b45..912513d3e67a9b 100644 --- a/diffcore-order.c +++ b/diffcore-order.c @@ -14,8 +14,7 @@ static void prepare_order(const char *orderfile) { int cnt, pass; struct strbuf sb = STRBUF_INIT; - void *map; - char *cp, *endp; + const char *cp, *endp; ssize_t sz; if (order) @@ -24,14 +23,13 @@ static void prepare_order(const char *orderfile) sz = strbuf_read_file(&sb, orderfile, 0); if (sz < 0) die_errno(_("failed to read orderfile '%s'"), orderfile); - map = strbuf_detach(&sb, NULL); - endp = (char *) map + sz; + endp = sb.buf + sz; for (pass = 0; pass < 2; pass++) { cnt = 0; - cp = map; + cp = sb.buf; while (cp < endp) { - char *ep; + const char *ep; for (ep = cp; ep < endp && *ep != '\n'; ep++) ; /* cp to ep has one line */ @@ -40,12 +38,7 @@ static void prepare_order(const char *orderfile) else if (pass == 0) cnt++; else { - if (*ep == '\n') { - *ep = 0; - order[cnt] = cp; - } else { - order[cnt] = xmemdupz(cp, ep - cp); - } + order[cnt] = xmemdupz(cp, ep - cp); cnt++; } if (ep < endp) @@ -57,6 +50,8 @@ static void prepare_order(const char *orderfile) ALLOC_ARRAY(order, cnt); } } + + strbuf_release(&sb); } static int match_order(const char *path) diff --git a/dir.c b/dir.c index 60c3eb21b413d7..90fabfa4ce00fd 100644 --- a/dir.c +++ b/dir.c @@ -2175,8 +2175,7 @@ static enum path_treatment treat_directory(struct dir_struct *dir, */ state = path_none; } else { - int i; - for (i = old_ignored_nr + 1; iignored_nr; ++i) + for (int i = old_ignored_nr; i < dir->ignored_nr; i++) FREE_AND_NULL(dir->ignored[i]); dir->ignored_nr = old_ignored_nr; } @@ -2188,8 +2187,7 @@ static enum path_treatment treat_directory(struct dir_struct *dir, */ if ((dir->flags & DIR_SHOW_IGNORED_TOO) && !(dir->flags & DIR_KEEP_UNTRACKED_CONTENTS)) { - int i; - for (i = old_untracked_nr + 1; inr; ++i) + for (int i = old_untracked_nr; i < dir->nr; i++) FREE_AND_NULL(dir->entries[i]); dir->nr = old_untracked_nr; } diff --git a/git.c b/git.c index 2658377a4124e4..1825350267470d 100644 --- a/git.c +++ b/git.c @@ -713,6 +713,7 @@ static void strip_extension(const char **argv) static void handle_builtin(int argc, const char **argv) { struct strvec args = STRVEC_INIT; + const char **argv_copy = NULL; const char *cmd; struct cmd_struct *builtin; @@ -733,13 +734,28 @@ static void handle_builtin(int argc, const char **argv) } argc++; - argv = args.v; + + /* + * `run_builtin()` will modify the argv array, so we need to + * create a shallow copy such that we can free all of its + * strings. + */ + CALLOC_ARRAY(argv_copy, argc + 1); + COPY_ARRAY(argv_copy, args.v, argc); + + argv = argv_copy; } builtin = get_builtin(cmd); - if (builtin) - exit(run_builtin(builtin, argc, argv, the_repository)); + if (builtin) { + int ret = run_builtin(builtin, argc, argv, the_repository); + strvec_clear(&args); + free(argv_copy); + exit(ret); + } + strvec_clear(&args); + free(argv_copy); } static void execv_dashed_external(const char **argv) diff --git a/grep.c b/grep.c index e5761426e4f0f3..701e58de04ef61 100644 --- a/grep.c +++ b/grep.c @@ -843,11 +843,11 @@ static void free_grep_pat(struct grep_pat *pattern) free_pcre2_pattern(p); else regfree(&p->regexp); - free(p->pattern); break; default: break; } + free(p->pattern); free(p); } } diff --git a/hash.h b/hash.h index 72ffbc862e557a..f97f858307be67 100644 --- a/hash.h +++ b/hash.h @@ -15,6 +15,36 @@ #include "block-sha1/sha1.h" #endif +#if defined(SHA1_APPLE_UNSAFE) +# include +# define platform_SHA_CTX_unsafe CC_SHA1_CTX +# define platform_SHA1_Init_unsafe CC_SHA1_Init +# define platform_SHA1_Update_unsafe CC_SHA1_Update +# define platform_SHA1_Final_unsafe CC_SHA1_Final +#elif defined(SHA1_OPENSSL_UNSAFE) +# include +# if defined(OPENSSL_API_LEVEL) && OPENSSL_API_LEVEL >= 3 +# define SHA1_NEEDS_CLONE_HELPER_UNSAFE +# include "sha1/openssl.h" +# define platform_SHA_CTX_unsafe openssl_SHA1_CTX +# define platform_SHA1_Init_unsafe openssl_SHA1_Init +# define platform_SHA1_Clone_unsafe openssl_SHA1_Clone +# define platform_SHA1_Update_unsafe openssl_SHA1_Update +# define platform_SHA1_Final_unsafe openssl_SHA1_Final +# else +# define platform_SHA_CTX_unsafe SHA_CTX +# define platform_SHA1_Init_unsafe SHA1_Init +# define platform_SHA1_Update_unsafe SHA1_Update +# define platform_SHA1_Final_unsafe SHA1_Final +# endif +#elif defined(SHA1_BLK_UNSAFE) +# include "block-sha1/sha1.h" +# define platform_SHA_CTX_unsafe blk_SHA_CTX +# define platform_SHA1_Init_unsafe blk_SHA1_Init +# define platform_SHA1_Update_unsafe blk_SHA1_Update +# define platform_SHA1_Final_unsafe blk_SHA1_Final +#endif + #if defined(SHA256_NETTLE) #include "sha256/nettle.h" #elif defined(SHA256_GCRYPT) @@ -44,14 +74,32 @@ #define platform_SHA1_Final SHA1_Final #endif +#ifndef platform_SHA_CTX_unsafe +# define platform_SHA_CTX_unsafe platform_SHA_CTX +# define platform_SHA1_Init_unsafe platform_SHA1_Init +# define platform_SHA1_Update_unsafe platform_SHA1_Update +# define platform_SHA1_Final_unsafe platform_SHA1_Final +# ifdef platform_SHA1_Clone +# define platform_SHA1_Clone_unsafe platform_SHA1_Clone +# endif +#endif + #define git_SHA_CTX platform_SHA_CTX #define git_SHA1_Init platform_SHA1_Init #define git_SHA1_Update platform_SHA1_Update #define git_SHA1_Final platform_SHA1_Final +#define git_SHA_CTX_unsafe platform_SHA_CTX_unsafe +#define git_SHA1_Init_unsafe platform_SHA1_Init_unsafe +#define git_SHA1_Update_unsafe platform_SHA1_Update_unsafe +#define git_SHA1_Final_unsafe platform_SHA1_Final_unsafe + #ifdef platform_SHA1_Clone #define git_SHA1_Clone platform_SHA1_Clone #endif +#ifdef platform_SHA1_Clone_unsafe +# define git_SHA1_Clone_unsafe platform_SHA1_Clone_unsafe +#endif #ifndef platform_SHA256_CTX #define platform_SHA256_CTX SHA256_CTX @@ -81,6 +129,13 @@ static inline void git_SHA1_Clone(git_SHA_CTX *dst, const git_SHA_CTX *src) memcpy(dst, src, sizeof(*dst)); } #endif +#ifndef SHA1_NEEDS_CLONE_HELPER_UNSAFE +static inline void git_SHA1_Clone_unsafe(git_SHA_CTX_unsafe *dst, + const git_SHA_CTX_unsafe *src) +{ + memcpy(dst, src, sizeof(*dst)); +} +#endif #ifndef SHA256_NEEDS_CLONE_HELPER static inline void git_SHA256_Clone(git_SHA256_CTX *dst, const git_SHA256_CTX *src) @@ -178,6 +233,8 @@ enum get_oid_result { /* A suitably aligned type for stack allocations of hash contexts. */ union git_hash_ctx { git_SHA_CTX sha1; + git_SHA_CTX_unsafe sha1_unsafe; + git_SHA256_CTX sha256; }; typedef union git_hash_ctx git_hash_ctx; @@ -222,6 +279,21 @@ struct git_hash_algo { /* The hash finalization function for object IDs. */ git_hash_final_oid_fn final_oid_fn; + /* The non-cryptographic hash initialization function. */ + git_hash_init_fn unsafe_init_fn; + + /* The non-cryptographic hash context cloning function. */ + git_hash_clone_fn unsafe_clone_fn; + + /* The non-cryptographic hash update function. */ + git_hash_update_fn unsafe_update_fn; + + /* The non-cryptographic hash finalization function. */ + git_hash_final_fn unsafe_final_fn; + + /* The non-cryptographic hash finalization function. */ + git_hash_final_oid_fn unsafe_final_oid_fn; + /* The OID of the empty tree. */ const struct object_id *empty_tree; diff --git a/http-fetch.c b/http-fetch.c index d460bb1837d06f..02ab80533f0e34 100644 --- a/http-fetch.c +++ b/http-fetch.c @@ -106,6 +106,7 @@ int cmd_main(int argc, const char **argv) int nongit; struct object_id packfile_hash; struct strvec index_pack_args = STRVEC_INIT; + int ret; setup_git_directory_gently(&nongit); @@ -157,8 +158,8 @@ int cmd_main(int argc, const char **argv) fetch_single_packfile(&packfile_hash, argv[arg], index_pack_args.v); - - return 0; + ret = 0; + goto out; } if (index_pack_args.nr) @@ -170,7 +171,12 @@ int cmd_main(int argc, const char **argv) commit_id = (char **) &argv[arg++]; commits = 1; } - return fetch_using_walker(argv[arg], get_verbosely, get_recover, - commits, commit_id, write_ref, - commits_on_stdin); + + ret = fetch_using_walker(argv[arg], get_verbosely, get_recover, + commits, commit_id, write_ref, + commits_on_stdin); + +out: + strvec_clear(&index_pack_args); + return ret; } diff --git a/http-push.c b/http-push.c index 7315a694aa4b8a..aad89f2eab3b52 100644 --- a/http-push.c +++ b/http-push.c @@ -275,7 +275,7 @@ static void start_fetch_loose(struct transfer_request *request) if (!start_active_slot(slot)) { fprintf(stderr, "Unable to start GET request\n"); repo->can_update_info_refs = 0; - release_http_object_request(obj_req); + release_http_object_request(&obj_req); release_request(request); } } @@ -375,7 +375,7 @@ static void start_put(struct transfer_request *request) /* Set it up */ git_deflate_init(&stream, zlib_compression_level); size = git_deflate_bound(&stream, len + hdrlen); - strbuf_init(&request->buffer.buf, size); + strbuf_grow(&request->buffer.buf, size); request->buffer.posn = 0; /* Compress it */ @@ -437,9 +437,11 @@ static void start_move(struct transfer_request *request) if (start_active_slot(slot)) { request->slot = slot; request->state = RUN_MOVE; + request->headers = dav_headers; } else { request->state = ABORTED; FREE_AND_NULL(request->url); + curl_slist_free_all(dav_headers); } } @@ -512,6 +514,8 @@ static void release_request(struct transfer_request *request) } free(request->url); + free(request->dest); + strbuf_release(&request->buffer.buf); free(request); } @@ -578,9 +582,10 @@ static void finish_request(struct transfer_request *request) if (obj_req->rename == 0) request->obj->flags |= (LOCAL | REMOTE); + release_http_object_request(&obj_req); + /* Try fetching packed if necessary */ if (request->obj->flags & LOCAL) { - release_http_object_request(obj_req); release_request(request); } else start_fetch_packed(request); @@ -649,12 +654,10 @@ static void add_fetch_request(struct object *obj) return; obj->flags |= FETCHING; - request = xmalloc(sizeof(*request)); + CALLOC_ARRAY(request, 1); request->obj = obj; - request->url = NULL; - request->lock = NULL; - request->headers = NULL; request->state = NEED_FETCH; + strbuf_init(&request->buffer.buf, 0); request->next = request_queue_head; request_queue_head = request; @@ -685,12 +688,11 @@ static int add_send_request(struct object *obj, struct remote_lock *lock) } obj->flags |= PUSHING; - request = xmalloc(sizeof(*request)); + CALLOC_ARRAY(request, 1); request->obj = obj; - request->url = NULL; request->lock = lock; - request->headers = NULL; request->state = NEED_PUSH; + strbuf_init(&request->buffer.buf, 0); request->next = request_queue_head; request_queue_head = request; @@ -912,6 +914,7 @@ static struct remote_lock *lock_remote(const char *path, long timeout) result = XML_Parse(parser, in_buffer.buf, in_buffer.len, 1); free(ctx.name); + free(ctx.cdata); if (result != XML_STATUS_OK) { fprintf(stderr, "XML error: %s\n", XML_ErrorString( @@ -1169,6 +1172,7 @@ static void remote_ls(const char *path, int flags, result = XML_Parse(parser, in_buffer.buf, in_buffer.len, 1); free(ctx.name); + free(ctx.cdata); if (result != XML_STATUS_OK) { fprintf(stderr, "XML error: %s\n", @@ -1182,6 +1186,7 @@ static void remote_ls(const char *path, int flags, } free(ls.path); + free(ls.dentry_name); free(url); strbuf_release(&out_buffer.buf); strbuf_release(&in_buffer); @@ -1370,9 +1375,13 @@ static int get_delta(struct rev_info *revs, struct remote_lock *lock) } while (objects) { + struct object_list *next = objects->next; + if (!(objects->item->flags & UNINTERESTING)) count += add_send_request(objects->item, lock); - objects = objects->next; + + free(objects); + objects = next; } return count; @@ -1398,6 +1407,7 @@ static int update_remote(const struct object_id *oid, struct remote_lock *lock) if (start_active_slot(slot)) { run_active_slot(slot); strbuf_release(&out_buffer.buf); + curl_slist_free_all(dav_headers); if (results.curl_result != CURLE_OK) { fprintf(stderr, "PUT error: curl result=%d, HTTP code=%ld\n", @@ -1407,6 +1417,7 @@ static int update_remote(const struct object_id *oid, struct remote_lock *lock) } } else { strbuf_release(&out_buffer.buf); + curl_slist_free_all(dav_headers); fprintf(stderr, "Unable to start PUT request\n"); return 0; } @@ -1516,6 +1527,7 @@ static void update_remote_info_refs(struct remote_lock *lock) results.curl_result, results.http_code); } } + curl_slist_free_all(dav_headers); } strbuf_release(&buffer.buf); } @@ -1707,7 +1719,7 @@ int cmd_main(int argc, const char **argv) int rc = 0; int i; int new_refs; - struct ref *ref, *local_refs; + struct ref *ref, *local_refs = NULL; CALLOC_ARRAY(repo, 1); @@ -1972,6 +1984,7 @@ int cmd_main(int argc, const char **argv) cleanup: if (info_ref_lock) unlock_remote(info_ref_lock); + free(repo->url); free(repo); http_cleanup(); @@ -1983,5 +1996,8 @@ int cmd_main(int argc, const char **argv) request = next_request; } + refspec_clear(&rs); + free_refs(local_refs); + return rc; } diff --git a/http-walker.c b/http-walker.c index e417a7f51ce3c3..fb2d86d5e70f0e 100644 --- a/http-walker.c +++ b/http-walker.c @@ -74,7 +74,7 @@ static void start_object_request(struct object_request *obj_req) obj_req->state = ACTIVE; if (!start_active_slot(slot)) { obj_req->state = ABORTED; - release_http_object_request(req); + release_http_object_request(&req); return; } } @@ -110,7 +110,7 @@ static void process_object_response(void *callback_data) if (obj_req->repo->next) { obj_req->repo = obj_req->repo->next; - release_http_object_request(obj_req->req); + release_http_object_request(&obj_req->req); start_object_request(obj_req); return; } @@ -495,7 +495,7 @@ static int fetch_object(struct walker *walker, unsigned char *hash) if (repo_has_object_file(the_repository, &obj_req->oid)) { if (obj_req->req) - abort_http_object_request(obj_req->req); + abort_http_object_request(&obj_req->req); abort_object_request(obj_req); return 0; } @@ -543,7 +543,7 @@ static int fetch_object(struct walker *walker, unsigned char *hash) strbuf_release(&buf); } - release_http_object_request(req); + release_http_object_request(&obj_req->req); release_object_request(obj_req); return ret; } @@ -579,8 +579,18 @@ static void cleanup(struct walker *walker) if (data) { alt = data->alt; while (alt) { + struct packed_git *pack; + alt_next = alt->next; + pack = alt->packs; + while (pack) { + struct packed_git *pack_next = pack->next; + close_pack(pack); + free(pack); + pack = pack_next; + } + free(alt->base); free(alt); diff --git a/http.c b/http.c index 192dc41163bcb3..9f229e866a0792 100644 --- a/http.c +++ b/http.c @@ -825,6 +825,7 @@ static int redact_sensitive_header(struct strbuf *header, size_t offset) strbuf_setlen(header, sensitive_header - header->buf); strbuf_addbuf(header, &redacted_header); + strbuf_release(&redacted_header); ret = 1; } return ret; @@ -2510,6 +2511,7 @@ int http_get_info_packs(const char *base_url, struct packed_git **packs_head) cleanup: free(url); + strbuf_release(&buf); return ret; } @@ -2761,6 +2763,7 @@ struct http_object_request *new_http_object_request(const char *base_url, * file; also rewind to the beginning of the local file. */ if (prev_read == -1) { + git_inflate_end(&freq->stream); memset(&freq->stream, 0, sizeof(freq->stream)); git_inflate_init(&freq->stream); the_hash_algo->init_fn(&freq->c); @@ -2834,7 +2837,6 @@ int finish_http_object_request(struct http_object_request *freq) return -1; } - git_inflate_end(&freq->stream); the_hash_algo->final_oid_fn(&freq->real_oid, &freq->c); if (freq->zret != Z_STREAM_END) { unlink_or_warn(freq->tmpfile.buf); @@ -2851,15 +2853,17 @@ int finish_http_object_request(struct http_object_request *freq) return freq->rename; } -void abort_http_object_request(struct http_object_request *freq) +void abort_http_object_request(struct http_object_request **freq_p) { + struct http_object_request *freq = *freq_p; unlink_or_warn(freq->tmpfile.buf); - release_http_object_request(freq); + release_http_object_request(freq_p); } -void release_http_object_request(struct http_object_request *freq) +void release_http_object_request(struct http_object_request **freq_p) { + struct http_object_request *freq = *freq_p; if (freq->localfile != -1) { close(freq->localfile); freq->localfile = -1; @@ -2873,4 +2877,8 @@ void release_http_object_request(struct http_object_request *freq) } curl_slist_free_all(freq->headers); strbuf_release(&freq->tmpfile); + git_inflate_end(&freq->stream); + + free(freq); + *freq_p = NULL; } diff --git a/http.h b/http.h index a516ca4a9a2db1..46e334c2c2f239 100644 --- a/http.h +++ b/http.h @@ -240,8 +240,8 @@ struct http_object_request *new_http_object_request( const char *base_url, const struct object_id *oid); void process_http_object_request(struct http_object_request *freq); int finish_http_object_request(struct http_object_request *freq); -void abort_http_object_request(struct http_object_request *freq); -void release_http_object_request(struct http_object_request *freq); +void abort_http_object_request(struct http_object_request **freq); +void release_http_object_request(struct http_object_request **freq); /* * Instead of using environment variables to determine if curl tracing happens, diff --git a/object-file.c b/object-file.c index b9a87ad43d680e..a19be7222a19af 100644 --- a/object-file.c +++ b/object-file.c @@ -115,6 +115,33 @@ static void git_hash_sha1_final_oid(struct object_id *oid, git_hash_ctx *ctx) oid->algo = GIT_HASH_SHA1; } +static void git_hash_sha1_init_unsafe(git_hash_ctx *ctx) +{ + git_SHA1_Init_unsafe(&ctx->sha1_unsafe); +} + +static void git_hash_sha1_clone_unsafe(git_hash_ctx *dst, const git_hash_ctx *src) +{ + git_SHA1_Clone_unsafe(&dst->sha1_unsafe, &src->sha1_unsafe); +} + +static void git_hash_sha1_update_unsafe(git_hash_ctx *ctx, const void *data, + size_t len) +{ + git_SHA1_Update_unsafe(&ctx->sha1_unsafe, data, len); +} + +static void git_hash_sha1_final_unsafe(unsigned char *hash, git_hash_ctx *ctx) +{ + git_SHA1_Final_unsafe(hash, &ctx->sha1_unsafe); +} + +static void git_hash_sha1_final_oid_unsafe(struct object_id *oid, git_hash_ctx *ctx) +{ + git_SHA1_Final_unsafe(oid->hash, &ctx->sha1_unsafe); + memset(oid->hash + GIT_SHA1_RAWSZ, 0, GIT_MAX_RAWSZ - GIT_SHA1_RAWSZ); + oid->algo = GIT_HASH_SHA1; +} static void git_hash_sha256_init(git_hash_ctx *ctx) { @@ -189,6 +216,11 @@ const struct git_hash_algo hash_algos[GIT_HASH_NALGOS] = { .update_fn = git_hash_unknown_update, .final_fn = git_hash_unknown_final, .final_oid_fn = git_hash_unknown_final_oid, + .unsafe_init_fn = git_hash_unknown_init, + .unsafe_clone_fn = git_hash_unknown_clone, + .unsafe_update_fn = git_hash_unknown_update, + .unsafe_final_fn = git_hash_unknown_final, + .unsafe_final_oid_fn = git_hash_unknown_final_oid, .empty_tree = NULL, .empty_blob = NULL, .null_oid = NULL, @@ -204,6 +236,11 @@ const struct git_hash_algo hash_algos[GIT_HASH_NALGOS] = { .update_fn = git_hash_sha1_update, .final_fn = git_hash_sha1_final, .final_oid_fn = git_hash_sha1_final_oid, + .unsafe_init_fn = git_hash_sha1_init_unsafe, + .unsafe_clone_fn = git_hash_sha1_clone_unsafe, + .unsafe_update_fn = git_hash_sha1_update_unsafe, + .unsafe_final_fn = git_hash_sha1_final_unsafe, + .unsafe_final_oid_fn = git_hash_sha1_final_oid_unsafe, .empty_tree = &empty_tree_oid, .empty_blob = &empty_blob_oid, .null_oid = &null_oid_sha1, @@ -219,6 +256,11 @@ const struct git_hash_algo hash_algos[GIT_HASH_NALGOS] = { .update_fn = git_hash_sha256_update, .final_fn = git_hash_sha256_final, .final_oid_fn = git_hash_sha256_final_oid, + .unsafe_init_fn = git_hash_sha256_init, + .unsafe_clone_fn = git_hash_sha256_clone, + .unsafe_update_fn = git_hash_sha256_update, + .unsafe_final_fn = git_hash_sha256_final, + .unsafe_final_oid_fn = git_hash_sha256_final_oid, .empty_tree = &empty_tree_oid_sha256, .empty_blob = &empty_blob_oid_sha256, .null_oid = &null_oid_sha256, @@ -1932,17 +1974,77 @@ static void write_object_file_prepare_literally(const struct git_hash_algo *algo hash_object_body(algo, &c, buf, len, oid, hdr, hdrlen); } +static int check_collision(const char *filename_a, const char *filename_b) +{ + char buf_a[4096], buf_b[4096]; + int fd_a = -1, fd_b = -1; + int ret = 0; + + fd_a = open(filename_a, O_RDONLY); + if (fd_a < 0) { + ret = error_errno(_("unable to open %s"), filename_a); + goto out; + } + + fd_b = open(filename_b, O_RDONLY); + if (fd_b < 0) { + ret = error_errno(_("unable to open %s"), filename_b); + goto out; + } + + while (1) { + ssize_t sz_a, sz_b; + + sz_a = read_in_full(fd_a, buf_a, sizeof(buf_a)); + if (sz_a < 0) { + ret = error_errno(_("unable to read %s"), filename_a); + goto out; + } + + sz_b = read_in_full(fd_b, buf_b, sizeof(buf_b)); + if (sz_b < 0) { + ret = error_errno(_("unable to read %s"), filename_b); + goto out; + } + + if (sz_a != sz_b || memcmp(buf_a, buf_b, sz_a)) { + ret = error(_("files '%s' and '%s' differ in contents"), + filename_a, filename_b); + goto out; + } + + if (sz_a < sizeof(buf_a)) + break; + } + +out: + if (fd_a > -1) + close(fd_a); + if (fd_b > -1) + close(fd_b); + return ret; +} + /* * Move the just written object into its final resting place. */ int finalize_object_file(const char *tmpfile, const char *filename) { + return finalize_object_file_flags(tmpfile, filename, 0); +} + +int finalize_object_file_flags(const char *tmpfile, const char *filename, + enum finalize_object_file_flags flags) +{ + struct stat st; int ret = 0; if (object_creation_mode == OBJECT_CREATION_USES_RENAMES) goto try_rename; else if (link(tmpfile, filename)) ret = errno; + else + unlink_or_warn(tmpfile); /* * Coda hack - coda doesn't like cross-directory links, @@ -1957,16 +2059,24 @@ int finalize_object_file(const char *tmpfile, const char *filename) */ if (ret && ret != EEXIST) { try_rename: - if (!rename(tmpfile, filename)) + if (!stat(filename, &st)) + ret = EEXIST; + else if (!rename(tmpfile, filename)) goto out; - ret = errno; + else + ret = errno; } - unlink_or_warn(tmpfile); if (ret) { if (ret != EEXIST) { + int saved_errno = errno; + unlink_or_warn(tmpfile); + errno = saved_errno; return error_errno(_("unable to write file %s"), filename); } - /* FIXME!!! Collision check here ? */ + if (!(flags & FOF_SKIP_COLLISION_CHECK) && + check_collision(tmpfile, filename)) + return -1; + unlink_or_warn(tmpfile); } out: @@ -2219,7 +2329,8 @@ static int write_loose_object(const struct object_id *oid, char *hdr, warning_errno(_("failed utime() on %s"), tmp_file.buf); } - return finalize_object_file(tmp_file.buf, filename.buf); + return finalize_object_file_flags(tmp_file.buf, filename.buf, + FOF_SKIP_COLLISION_CHECK); } static int freshen_loose_object(const struct object_id *oid) @@ -2341,7 +2452,8 @@ int stream_loose_object(struct input_stream *in_stream, size_t len, strbuf_release(&dir); } - err = finalize_object_file(tmp_file.buf, filename.buf); + err = finalize_object_file_flags(tmp_file.buf, filename.buf, + FOF_SKIP_COLLISION_CHECK); if (!err && compat) err = repo_add_loose_object_map(the_repository, oid, &compat_oid); cleanup: diff --git a/object-file.h b/object-file.h index d6414610f80b73..81b30d269c82e4 100644 --- a/object-file.h +++ b/object-file.h @@ -117,7 +117,13 @@ int check_object_signature(struct repository *r, const struct object_id *oid, */ int stream_object_signature(struct repository *r, const struct object_id *oid); +enum finalize_object_file_flags { + FOF_SKIP_COLLISION_CHECK = 1, +}; + int finalize_object_file(const char *tmpfile, const char *filename); +int finalize_object_file_flags(const char *tmpfile, const char *filename, + enum finalize_object_file_flags flags); /* Helper to check and "touch" a file */ int check_and_freshen_file(const char *fn, int freshen); diff --git a/pack-write.c b/pack-write.c index 27965672f17822..f415604c15990b 100644 --- a/pack-write.c +++ b/pack-write.c @@ -8,6 +8,7 @@ #include "csum-file.h" #include "remote.h" #include "chunk-format.h" +#include "object-file.h" #include "pack-mtimes.h" #include "pack-objects.h" #include "pack-revindex.h" @@ -528,9 +529,9 @@ static void rename_tmp_packfile(struct strbuf *name_prefix, const char *source, size_t name_prefix_len = name_prefix->len; strbuf_addstr(name_prefix, ext); - if (rename(source, name_prefix->buf)) - die_errno("unable to rename temporary file to '%s'", - name_prefix->buf); + if (finalize_object_file(source, name_prefix->buf)) + die("unable to rename temporary file to '%s'", + name_prefix->buf); strbuf_setlen(name_prefix, name_prefix_len); } diff --git a/parse-options.c b/parse-options.c index 30b9e68f8ac85d..33bfba0ed4a0ea 100644 --- a/parse-options.c +++ b/parse-options.c @@ -60,12 +60,12 @@ static enum parse_opt_result get_arg(struct parse_opt_ctx_t *p, return 0; } -static void fix_filename(const char *prefix, char **file) +static char *fix_filename(const char *prefix, const char *file) { if (!file || !*file) - ; /* leave as NULL */ + return NULL; else - *file = prefix_filename_except_for_dash(prefix, *file); + return prefix_filename_except_for_dash(prefix, file); } static enum parse_opt_result do_get_value(struct parse_opt_ctx_t *p, @@ -129,18 +129,24 @@ static enum parse_opt_result do_get_value(struct parse_opt_ctx_t *p, return 0; case OPTION_FILENAME: + { + const char *value; + + FREE_AND_NULL(*(char **)opt->value); + err = 0; + if (unset) - *(const char **)opt->value = NULL; + value = NULL; else if (opt->flags & PARSE_OPT_OPTARG && !p->opt) - *(const char **)opt->value = (const char *)opt->defval; + value = (const char *) opt->defval; else - err = get_arg(p, opt, flags, (const char **)opt->value); + err = get_arg(p, opt, flags, &value); if (!err) - fix_filename(p->prefix, (char **)opt->value); + *(char **)opt->value = fix_filename(p->prefix, value); return err; - + } case OPTION_CALLBACK: { const char *p_arg = NULL; diff --git a/promisor-remote.c b/promisor-remote.c index 317e1b127fede4..9345ae3db235fb 100644 --- a/promisor-remote.c +++ b/promisor-remote.c @@ -154,6 +154,7 @@ static int promisor_remote_config(const char *var, const char *value, if (!r) return 0; + FREE_AND_NULL(r->partial_clone_filter); return git_config_string(&r->partial_clone_filter, var, value); } @@ -189,6 +190,7 @@ void promisor_remote_clear(struct promisor_remote_config *config) { while (config->promisors) { struct promisor_remote *r = config->promisors; + free(r->partial_clone_filter); config->promisors = config->promisors->next; free(r); } diff --git a/refs/reftable-backend.c b/refs/reftable-backend.c index f5f957e6de428a..3c96fbf66f9e20 100644 --- a/refs/reftable-backend.c +++ b/refs/reftable-backend.c @@ -260,6 +260,13 @@ static int reftable_be_config(const char *var, const char *value, if (factor > UINT8_MAX) die("reftable geometric factor cannot exceed %u", (unsigned)UINT8_MAX); opts->auto_compaction_factor = factor; + } else if (!strcmp(var, "reftable.locktimeout")) { + int64_t lock_timeout = git_config_int64(var, value, ctx->kvi); + if (lock_timeout > LONG_MAX) + die("reftable lock timeout cannot exceed %"PRIdMAX, (intmax_t)LONG_MAX); + if (lock_timeout < 0 && lock_timeout != -1) + die("reftable lock timeout does not support negative values other than -1"); + opts->lock_timeout_ms = lock_timeout; } return 0; @@ -286,6 +293,7 @@ static struct ref_store *reftable_be_init(struct repository *repo, refs->write_options.default_permissions = calc_shared_perm(0666 & ~mask); refs->write_options.disable_auto_compact = !git_env_bool("GIT_TEST_REFTABLE_AUTOCOMPACTION", 1); + refs->write_options.lock_timeout_ms = 100; git_config(reftable_be_config, &refs->write_options); @@ -893,7 +901,8 @@ static int prepare_transaction_update(struct write_transaction_table_arg **out, if (ret) return ret; - ret = reftable_stack_new_addition(&addition, stack); + ret = reftable_stack_new_addition(&addition, stack, + REFTABLE_STACK_NEW_ADDITION_RELOAD); if (ret) { if (ret == REFTABLE_LOCK_ERROR) strbuf_addstr(err, "cannot lock references"); @@ -2330,7 +2339,7 @@ static int reftable_be_reflog_expire(struct ref_store *ref_store, if (ret < 0) goto done; - ret = reftable_stack_new_addition(&add, stack); + ret = reftable_stack_new_addition(&add, stack, 0); if (ret < 0) goto done; diff --git a/refspec.c b/refspec.c index ec90ab349a2914..c3cf003443dd36 100644 --- a/refspec.c +++ b/refspec.c @@ -225,7 +225,7 @@ void refspec_clear(struct refspec *rs) rs->nr = 0; for (i = 0; i < rs->raw_nr; i++) - free((char *)rs->raw[i]); + free(rs->raw[i]); FREE_AND_NULL(rs->raw); rs->raw_alloc = 0; rs->raw_nr = 0; diff --git a/refspec.h b/refspec.h index 754be45cee3ce5..3760fdaf2bb183 100644 --- a/refspec.h +++ b/refspec.h @@ -43,7 +43,7 @@ struct refspec { int alloc; int nr; - const char **raw; + char **raw; int raw_alloc; int raw_nr; diff --git a/reftable/reftable-stack.h b/reftable/reftable-stack.h index f4f8cabc7fb560..6370fe45ddfa00 100644 --- a/reftable/reftable-stack.h +++ b/reftable/reftable-stack.h @@ -37,12 +37,21 @@ uint64_t reftable_stack_next_update_index(struct reftable_stack *st); /* holds a transaction to add tables at the top of a stack. */ struct reftable_addition; +enum { + /* + * Reload the stack when the stack is out-of-date after locking it. + */ + REFTABLE_STACK_NEW_ADDITION_RELOAD = (1 << 0), +}; + /* * returns a new transaction to add reftables to the given stack. As a side - * effect, the ref database is locked. + * effect, the ref database is locked. Accepts REFTABLE_STACK_NEW_ADDITION_* + * flags. */ int reftable_stack_new_addition(struct reftable_addition **dest, - struct reftable_stack *st); + struct reftable_stack *st, + unsigned int flags); /* Adds a reftable to transaction. */ int reftable_addition_add(struct reftable_addition *add, diff --git a/reftable/reftable-writer.h b/reftable/reftable-writer.h index 189b1f4144f228..f5e25cfda163d9 100644 --- a/reftable/reftable-writer.h +++ b/reftable/reftable-writer.h @@ -51,6 +51,17 @@ struct reftable_write_options { * tables to compact. Defaults to 2 if unset. */ uint8_t auto_compaction_factor; + + /* + * The number of milliseconds to wait when trying to lock "tables.list". + * Note that this does not apply to locking individual tables, as these + * should only ever be locked when already holding the "tables.list" + * lock. + * + * Passing 0 will fail immediately when the file is locked, passing a + * negative value will cause us to block indefinitely. + */ + long lock_timeout_ms; }; /* reftable_block_stats holds statistics for a single block type */ diff --git a/reftable/stack.c b/reftable/stack.c index ce0a35216bad6d..84cf37a2ad03ea 100644 --- a/reftable/stack.c +++ b/reftable/stack.c @@ -596,15 +596,18 @@ struct reftable_addition { #define REFTABLE_ADDITION_INIT {0} static int reftable_stack_init_addition(struct reftable_addition *add, - struct reftable_stack *st) + struct reftable_stack *st, + unsigned int flags) { struct strbuf lock_file_name = STRBUF_INIT; int err; add->stack = st; - err = hold_lock_file_for_update(&add->tables_list_lock, st->list_file, - LOCK_NO_DEREF); + err = hold_lock_file_for_update_timeout(&add->tables_list_lock, + st->list_file, + LOCK_NO_DEREF, + st->opts.lock_timeout_ms); if (err < 0) { if (errno == EEXIST) { err = REFTABLE_LOCK_ERROR; @@ -624,6 +627,11 @@ static int reftable_stack_init_addition(struct reftable_addition *add, err = stack_uptodate(st); if (err < 0) goto done; + if (err > 0 && flags & REFTABLE_STACK_NEW_ADDITION_RELOAD) { + err = reftable_stack_reload_maybe_reuse(add->stack, 1); + if (err) + goto done; + } if (err > 0) { err = REFTABLE_OUTDATED_ERROR; goto done; @@ -631,9 +639,8 @@ static int reftable_stack_init_addition(struct reftable_addition *add, add->next_update_index = reftable_stack_next_update_index(st); done: - if (err) { + if (err) reftable_addition_close(add); - } strbuf_release(&lock_file_name); return err; } @@ -737,13 +744,14 @@ int reftable_addition_commit(struct reftable_addition *add) } int reftable_stack_new_addition(struct reftable_addition **dest, - struct reftable_stack *st) + struct reftable_stack *st, + unsigned int flags) { int err = 0; struct reftable_addition empty = REFTABLE_ADDITION_INIT; REFTABLE_CALLOC_ARRAY(*dest, 1); **dest = empty; - err = reftable_stack_init_addition(*dest, st); + err = reftable_stack_init_addition(*dest, st, flags); if (err) { reftable_free(*dest); *dest = NULL; @@ -757,7 +765,7 @@ static int stack_try_add(struct reftable_stack *st, void *arg) { struct reftable_addition add = REFTABLE_ADDITION_INIT; - int err = reftable_stack_init_addition(&add, st); + int err = reftable_stack_init_addition(&add, st, 0); if (err < 0) goto done; @@ -1056,8 +1064,10 @@ static int stack_compact_range(struct reftable_stack *st, * Hold the lock so that we can read "tables.list" and lock all tables * which are part of the user-specified range. */ - err = hold_lock_file_for_update(&tables_list_lock, st->list_file, - LOCK_NO_DEREF); + err = hold_lock_file_for_update_timeout(&tables_list_lock, + st->list_file, + LOCK_NO_DEREF, + st->opts.lock_timeout_ms); if (err < 0) { if (errno == EEXIST) err = REFTABLE_LOCK_ERROR; @@ -1156,8 +1166,10 @@ static int stack_compact_range(struct reftable_stack *st, * "tables.list". We'll then replace the compacted range of tables with * the new table. */ - err = hold_lock_file_for_update(&tables_list_lock, st->list_file, - LOCK_NO_DEREF); + err = hold_lock_file_for_update_timeout(&tables_list_lock, + st->list_file, + LOCK_NO_DEREF, + st->opts.lock_timeout_ms); if (err < 0) { if (errno == EEXIST) err = REFTABLE_LOCK_ERROR; @@ -1602,7 +1614,7 @@ static int reftable_stack_clean_locked(struct reftable_stack *st) int reftable_stack_clean(struct reftable_stack *st) { struct reftable_addition *add = NULL; - int err = reftable_stack_new_addition(&add, st); + int err = reftable_stack_new_addition(&add, st, 0); if (err < 0) { goto done; } diff --git a/remote-curl.c b/remote-curl.c index 4adcf25ed6eeb5..9a71e043018847 100644 --- a/remote-curl.c +++ b/remote-curl.c @@ -347,7 +347,7 @@ static struct ref *parse_info_refs(struct discovery *heads) ref->next = refs; refs = ref; } else { - free(ref); + free_one_ref(ref); } return refs; diff --git a/remote.c b/remote.c index 390a03c2643db6..e291e8ff5cddb2 100644 --- a/remote.c +++ b/remote.c @@ -2544,7 +2544,7 @@ struct ref *get_stale_heads(struct refspec *rs, struct ref *fetch_map) /* * Compare-and-swap */ -static void clear_cas_option(struct push_cas_option *cas) +void clear_cas_option(struct push_cas_option *cas) { int i; diff --git a/remote.h b/remote.h index a58713f20ad654..ad4513f6394bed 100644 --- a/remote.h +++ b/remote.h @@ -409,6 +409,7 @@ struct push_cas_option { }; int parseopt_push_cas_option(const struct option *, const char *arg, int unset); +void clear_cas_option(struct push_cas_option *); int is_empty_cas(const struct push_cas_option *); void apply_push_cas(struct push_cas_option *, struct remote *, struct ref *); diff --git a/repo-settings.c b/repo-settings.c index 3885e81b97d170..d8123b9323d23e 100644 --- a/repo-settings.c +++ b/repo-settings.c @@ -3,8 +3,6 @@ #include "repo-settings.h" #include "repository.h" #include "midx.h" -#include "fsmonitor-ipc.h" -#include "fsmonitor-settings.h" static void repo_cfg_bool(struct repository *r, const char *key, int *dest, int def) @@ -48,30 +46,6 @@ void prepare_repo_settings(struct repository *r) r->settings.pack_use_bitmap_boundary_traversal = 1; r->settings.pack_use_multi_pack_reuse = 1; r->settings.pack_use_path_walk = 1; - - /* - * Force enable the builtin FSMonitor (unless the repo - * is incompatible or they've already selected it or - * the hook version). But only if they haven't - * explicitly turned it off -- so only if our config - * value is UNSET. - * - * lookup_fsmonitor_settings() and check_for_ipc() do - * not distinguish between explicitly set FALSE and - * UNSET, so we re-test for an UNSET config key here. - * - * I'm not sure I want to fix fsmonitor-settings.c to - * have more than one _DISABLED state since our usage - * here is only to support this experimental period - * (and I don't want to overload the _reason field - * because it describes incompabilities). - */ - if (manyfiles && - fsmonitor_ipc__is_supported() && - fsm_settings__get_mode(r) == FSMONITOR_MODE_DISABLED && - repo_config_get_maybe_bool(r, "core.fsmonitor", &value) > 0 && - repo_config_get_bool(r, "core.useBuiltinFSMonitor", &value)) - fsm_settings__set_ipc(r); } if (manyfiles) { r->settings.index_version = 4; diff --git a/revision.c b/revision.c index 750ecfe89f257c..cea6bde7227b99 100644 --- a/revision.c +++ b/revision.c @@ -1086,7 +1086,11 @@ static void try_to_simplify_commit(struct rev_info *revs, struct commit *commit) ts->treesame[nth_parent] = 1; continue; } + + free_commit_list(parent->next); parent->next = NULL; + while (commit->parents != parent) + pop_commit(&commit->parents); commit->parents = parent; /* @@ -1118,6 +1122,7 @@ static void try_to_simplify_commit(struct rev_info *revs, struct commit *commit) die("cannot simplify commit %s (invalid %s)", oid_to_hex(&commit->object.oid), oid_to_hex(&p->object.oid)); + free_commit_list(p->parents); p->parents = NULL; } /* fallthrough */ diff --git a/scalar.c b/scalar.c index b9c33f8c7a40d8..7db9c5bbfe03df 100644 --- a/scalar.c +++ b/scalar.c @@ -734,6 +734,9 @@ static int cmd_reconfigure(int argc, const char **argv) the_repository = old_repo; + if (toggle_maintenance(1) >= 0) + succeeded = 1; + loop_end: if (!succeeded) { res = -1; diff --git a/sha1/openssl.h b/sha1/openssl.h index 006c1f4ba541cb..1038af47dafa79 100644 --- a/sha1/openssl.h +++ b/sha1/openssl.h @@ -40,10 +40,12 @@ static inline void openssl_SHA1_Clone(struct openssl_SHA1_CTX *dst, EVP_MD_CTX_copy_ex(dst->ectx, src->ectx); } +#ifndef platform_SHA_CTX #define platform_SHA_CTX openssl_SHA1_CTX #define platform_SHA1_Init openssl_SHA1_Init #define platform_SHA1_Clone openssl_SHA1_Clone #define platform_SHA1_Update openssl_SHA1_Update #define platform_SHA1_Final openssl_SHA1_Final +#endif #endif /* SHA1_OPENSSL_H */ diff --git a/sha1dc_git.h b/sha1dc_git.h index 159540e13a382a..0bcf1aa84b7241 100644 --- a/sha1dc_git.h +++ b/sha1dc_git.h @@ -18,7 +18,10 @@ void git_SHA1DCFinal(unsigned char [20], SHA1_CTX *); void git_SHA1DCUpdate(SHA1_CTX *ctx, const void *data, size_t len); #define platform_SHA_IS_SHA1DC /* used by "test-tool sha1-is-sha1dc" */ + +#ifndef platform_SHA_CTX #define platform_SHA_CTX SHA1_CTX #define platform_SHA1_Init git_SHA1DCInit #define platform_SHA1_Update git_SHA1DCUpdate #define platform_SHA1_Final git_SHA1DCFinal +#endif diff --git a/shallow.c b/shallow.c index dcebc263d704ce..4bb1518dbc8074 100644 --- a/shallow.c +++ b/shallow.c @@ -51,12 +51,11 @@ int unregister_shallow(const struct object_id *oid) int pos = commit_graft_pos(the_repository, oid); if (pos < 0) return -1; - if (pos + 1 < the_repository->parsed_objects->grafts_nr) { - free(the_repository->parsed_objects->grafts[pos]); + free(the_repository->parsed_objects->grafts[pos]); + if (pos + 1 < the_repository->parsed_objects->grafts_nr) MOVE_ARRAY(the_repository->parsed_objects->grafts + pos, the_repository->parsed_objects->grafts + pos + 1, the_repository->parsed_objects->grafts_nr - pos - 1); - } the_repository->parsed_objects->grafts_nr--; return 0; } diff --git a/sparse-index.c b/sparse-index.c index 542ca5f411ca52..3d7f2164e25ee5 100644 --- a/sparse-index.c +++ b/sparse-index.c @@ -21,9 +21,10 @@ * advice for advice.sparseIndexExpanded when expanding a sparse index to a full * one. However, this is sometimes done on purpose, such as in the sparse-checkout * builtin, even when index.sparse=false. This may be disabled in - * convert_to_sparse(). + * convert_to_sparse() or by commands that know they will lead to a full + * expansion, but this message is not actionable. */ -static int give_advice_on_expansion = 1; +int give_advice_on_expansion = 1; #define ADVICE_MSG \ "The sparse index is expanding to a full index, a slow operation.\n" \ "Your working directory likely has contents that are outside of\n" \ diff --git a/sparse-index.h b/sparse-index.h index a16f3e67d75913..727034be7ca917 100644 --- a/sparse-index.h +++ b/sparse-index.h @@ -1,6 +1,13 @@ #ifndef SPARSE_INDEX_H__ #define SPARSE_INDEX_H__ +/* + * If performing an operation where the index is supposed to expand to a + * full index, then disable the advice message by setting this global to + * zero. + */ +extern int give_advice_on_expansion; + struct index_state; #define SPARSE_INDEX_MEMORY_ONLY (1 << 0) int is_sparse_index_allowed(struct index_state *istate, int flags); diff --git a/submodule-config.c b/submodule-config.c index c8f2bb2bdd3ef2..471637a725afd7 100644 --- a/submodule-config.c +++ b/submodule-config.c @@ -95,7 +95,7 @@ static void free_one_config(struct submodule_entry *entry) free((void *) entry->config->branch); free((void *) entry->config->url); free((void *) entry->config->ignore); - free((void *) entry->config->update_strategy.command); + submodule_update_strategy_release(&entry->config->update_strategy); free(entry->config); } diff --git a/submodule.c b/submodule.c index 4e71ac0dfdecea..74d5766f07c311 100644 --- a/submodule.c +++ b/submodule.c @@ -175,11 +175,11 @@ void stage_updated_gitmodules(struct index_state *istate) die(_("staging updated .gitmodules failed")); } -static struct string_list added_submodule_odb_paths = STRING_LIST_INIT_NODUP; +static struct string_list added_submodule_odb_paths = STRING_LIST_INIT_DUP; void add_submodule_odb_by_path(const char *path) { - string_list_insert(&added_submodule_odb_paths, xstrdup(path)); + string_list_insert(&added_submodule_odb_paths, path); } int register_all_submodule_odb_as_alternates(void) @@ -424,6 +424,11 @@ int parse_submodule_update_strategy(const char *value, return 0; } +void submodule_update_strategy_release(struct submodule_update_strategy *strategy) +{ + free((char *) strategy->command); +} + const char *submodule_update_type_to_string(enum submodule_update_type type) { switch (type) { diff --git a/submodule.h b/submodule.h index b50d29eba4f13a..4deb1b5f84e71e 100644 --- a/submodule.h +++ b/submodule.h @@ -41,6 +41,10 @@ struct submodule_update_strategy { .type = SM_UPDATE_UNSPECIFIED, \ } +int parse_submodule_update_strategy(const char *value, + struct submodule_update_strategy *dst); +void submodule_update_strategy_release(struct submodule_update_strategy *strategy); + int is_gitmodules_unmerged(struct index_state *istate); int is_writing_gitmodules_ok(void); int is_staging_gitmodules_ok(struct index_state *istate); @@ -70,8 +74,6 @@ void die_in_unpopulated_submodule(struct index_state *istate, void die_path_inside_submodule(struct index_state *istate, const struct pathspec *ps); enum submodule_update_type parse_submodule_update_type(const char *value); -int parse_submodule_update_strategy(const char *value, - struct submodule_update_strategy *dst); const char *submodule_update_type_to_string(enum submodule_update_type type); void handle_ignore_submodules_arg(struct diff_options *, const char *); void show_submodule_diff_summary(struct diff_options *o, const char *path, diff --git a/t/helper/test-submodule-nested-repo-config.c b/t/helper/test-submodule-nested-repo-config.c index 6ca069ce63370d..6dce957153112a 100644 --- a/t/helper/test-submodule-nested-repo-config.c +++ b/t/helper/test-submodule-nested-repo-config.c @@ -29,6 +29,6 @@ int cmd__submodule_nested_repo_config(int argc, const char **argv) print_config_from_gitmodules(&subrepo, argv[2]); submodule_free(the_repository); - + repo_clear(&subrepo); return 0; } diff --git a/t/t0012-help.sh b/t/t0012-help.sh index 1d273d91c2125a..9eae0d83563788 100755 --- a/t/t0012-help.sh +++ b/t/t0012-help.sh @@ -2,6 +2,7 @@ test_description='help' +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh configure_help () { diff --git a/t/t0610-reftable-basics.sh b/t/t0610-reftable-basics.sh index 37510c2b2a513e..ad7bb39b7912bd 100755 --- a/t/t0610-reftable-basics.sh +++ b/t/t0610-reftable-basics.sh @@ -423,6 +423,64 @@ test_expect_success 'ref transaction: fails gracefully when auto compaction fail ) ' +test_expect_success 'ref transaction: timeout acquiring tables.list lock' ' + test_when_finished "rm -rf repo" && + git init repo && + ( + cd repo && + test_commit initial && + >.git/reftable/tables.list.lock && + test_must_fail git update-ref refs/heads/branch HEAD 2>err && + test_grep "cannot lock references" err + ) +' + +test_expect_success 'ref transaction: retry acquiring tables.list lock' ' + test_when_finished "rm -rf repo" && + git init repo && + ( + cd repo && + test_commit initial && + LOCK=.git/reftable/tables.list.lock && + >$LOCK && + { + ( sleep 1 && rm -f $LOCK ) & + } && + git -c reftable.lockTimeout=5000 update-ref refs/heads/branch HEAD + ) +' + +test_expect_success !WINDOWS 'ref transaction: many concurrent writers' ' + test_when_finished "rm -rf repo" && + git init repo && + ( + cd repo && + # Set a high timeout such that a busy CI machine will not abort + # early. 10 seconds should hopefully be ample of time to make + # this non-flaky. + git config set reftable.lockTimeout 10000 && + test_commit --no-tag initial && + + head=$(git rev-parse HEAD) && + for i in $(test_seq 100) + do + printf "%s commit\trefs/heads/branch-%s\n" "$head" "$i" || + return 1 + done >expect && + printf "%s commit\trefs/heads/main\n" "$head" >>expect && + + for i in $(test_seq 100) + do + { git update-ref refs/heads/branch-$i HEAD& } || + return 1 + done && + + wait && + git for-each-ref --sort=v:refname >actual && + test_cmp expect actual + ) +' + test_expect_success 'pack-refs: compacts tables' ' test_when_finished "rm -rf repo" && git init repo && diff --git a/t/t1092-sparse-checkout-compatibility.sh b/t/t1092-sparse-checkout-compatibility.sh index eb32da2a7f2ad6..6e230b54876061 100755 --- a/t/t1092-sparse-checkout-compatibility.sh +++ b/t/t1092-sparse-checkout-compatibility.sh @@ -2355,7 +2355,10 @@ test_expect_success 'advice.sparseIndexExpanded' ' mkdir -p sparse-index/deep/deeper2/deepest && touch sparse-index/deep/deeper2/deepest/bogus && git -C sparse-index status 2>err && - grep "The sparse index is expanding to a full index" err + grep "The sparse index is expanding to a full index" err && + + git -C sparse-index sparse-checkout disable 2>err && + test_line_count = 0 err ' test_expect_success 'cat-file -p' ' diff --git a/t/t1305-config-include.sh b/t/t1305-config-include.sh index 5cde79ef8c4fa3..517d6c869379bf 100755 --- a/t/t1305-config-include.sh +++ b/t/t1305-config-include.sh @@ -357,4 +357,44 @@ test_expect_success 'include cycles are detected' ' grep "exceeded maximum include depth" stderr ' +test_expect_success 'onbranch with unborn branch' ' + test_when_finished "rm -rf repo" && + git init repo && + ( + cd repo && + git config set includeIf.onbranch:"*".path config.inc && + git config set -f .git/config.inc foo.bar baz && + git config get foo.bar + ) +' + +test_expect_success 'onbranch with detached HEAD' ' + test_when_finished "rm -rf repo" && + git init repo && + ( + cd repo && + git config set "includeIf.onbranch:*.path" config.inc && + git config set -f .git/config.inc foo.bar baz && + test_commit initial && + git switch --detach HEAD && + test_must_fail git config get foo.bar + ) +' + +test_expect_success 'onbranch without repository' ' + test_when_finished "rm -f .gitconfig config.inc" && + git config set -f .gitconfig "includeIf.onbranch:**.path" config.inc && + git config set -f config.inc foo.bar baz && + git config get foo.bar && + test_must_fail nongit git config get foo.bar +' + +test_expect_success 'onbranch without repository but explicit nonexistent Git directory' ' + test_when_finished "rm -f .gitconfig config.inc" && + git config set -f .gitconfig "includeIf.onbranch:**.path" config.inc && + git config set -f config.inc foo.bar baz && + git config get foo.bar && + test_must_fail nongit git --git-dir=nonexistent config get foo.bar +' + test_done diff --git a/t/t1414-reflog-walk.sh b/t/t1414-reflog-walk.sh index be6c3f472c1765..49d28166da0d93 100755 --- a/t/t1414-reflog-walk.sh +++ b/t/t1414-reflog-walk.sh @@ -4,6 +4,7 @@ test_description='various tests of reflog walk (log -g) behavior' GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success 'set up some reflog entries' ' diff --git a/t/t3011-common-prefixes-and-directory-traversal.sh b/t/t3011-common-prefixes-and-directory-traversal.sh index 3da5b2b6e795ec..69e44c387fa83c 100755 --- a/t/t3011-common-prefixes-and-directory-traversal.sh +++ b/t/t3011-common-prefixes-and-directory-traversal.sh @@ -2,6 +2,7 @@ test_description='directory traversal handling, especially with common prefixes' +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success 'setup' ' diff --git a/t/t4008-diff-break-rewrite.sh b/t/t4008-diff-break-rewrite.sh index 562aaf3a2a295e..b0ef0026e089ca 100755 --- a/t/t4008-diff-break-rewrite.sh +++ b/t/t4008-diff-break-rewrite.sh @@ -21,6 +21,8 @@ With -B, this should be detected as two complete rewrites. Further, with -B and -M together, these should turn into two renames. ' + +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh . "$TEST_DIRECTORY"/lib-diff.sh ;# test-lib chdir's into trash diff --git a/t/t4022-diff-rewrite.sh b/t/t4022-diff-rewrite.sh index 6fed993ea0b34d..77bc36d5d8fd98 100755 --- a/t/t4022-diff-rewrite.sh +++ b/t/t4022-diff-rewrite.sh @@ -2,6 +2,7 @@ test_description='rewrite diff' +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh . "$TEST_DIRECTORY"/lib-diff-data.sh diff --git a/t/t4023-diff-rename-typechange.sh b/t/t4023-diff-rename-typechange.sh index 787605ce3fd076..e6f4fe441e1b0d 100755 --- a/t/t4023-diff-rename-typechange.sh +++ b/t/t4023-diff-rename-typechange.sh @@ -2,6 +2,7 @@ test_description='typechange rename detection' +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh . "$TEST_DIRECTORY"/lib-diff.sh diff --git a/t/t4031-diff-rewrite-binary.sh b/t/t4031-diff-rewrite-binary.sh index c4394a27b56236..1b8cd3e4c97dd8 100755 --- a/t/t4031-diff-rewrite-binary.sh +++ b/t/t4031-diff-rewrite-binary.sh @@ -2,6 +2,7 @@ test_description='rewrite diff on binary file' +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh # We must be large enough to meet the MINIMUM_BREAK_SIZE diff --git a/t/t4056-diff-order.sh b/t/t4056-diff-order.sh index aec1d9d1b42f65..32c5fcb9a27c2e 100755 --- a/t/t4056-diff-order.sh +++ b/t/t4056-diff-order.sh @@ -5,6 +5,7 @@ test_description='diff order & rotate' GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh create_files () { diff --git a/t/t4204-patch-id.sh b/t/t4204-patch-id.sh index 605faea0c7baae..8e0f283c2b8f4d 100755 --- a/t/t4204-patch-id.sh +++ b/t/t4204-patch-id.sh @@ -5,6 +5,7 @@ test_description='git patch-id' GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success 'setup' ' diff --git a/t/t5000-tar-tree.sh b/t/t5000-tar-tree.sh index 7abba8a4b20caa..b9fda973f7bfbf 100755 --- a/t/t5000-tar-tree.sh +++ b/t/t5000-tar-tree.sh @@ -137,6 +137,8 @@ test_expect_success 'end-of-options is correctly eaten' ' test_expect_success 'populate workdir' ' mkdir a && + echo "a files_named_a" >.gitattributes && + git add .gitattributes && echo simple textfile >a/a && ten=0123456789 && hundred="$ten$ten$ten$ten$ten$ten$ten$ten$ten$ten" && @@ -450,6 +452,16 @@ test_expect_success 'allow pathspecs that resolve to the current directory' ' test_cmp expect actual ' +test_expect_success 'attr pathspec in bare repo' ' + test_expect_code 0 git --git-dir=bare.git archive -v HEAD \ + ":(attr:files_named_a)" >/dev/null 2>actual && + cat >expect <<-\EOF && + a/ + a/a + EOF + test_cmp expect actual +' + # Pull the size and date of each entry in a tarfile using the system tar. # # We'll pull out only the year from the date; that avoids any question of diff --git a/t/t5303-pack-corruption-resilience.sh b/t/t5303-pack-corruption-resilience.sh index 61469ef4a68120..e6a43ec9ae3c6d 100755 --- a/t/t5303-pack-corruption-resilience.sh +++ b/t/t5303-pack-corruption-resilience.sh @@ -44,9 +44,14 @@ create_new_pack() { } do_repack() { + for f in $pack.* + do + mv $f "$(echo $f | sed -e 's/pack-/pack-corrupt-/')" || return 1 + done && pack=$(printf "$blob_1\n$blob_2\n$blob_3\n" | git pack-objects $@ .git/objects/pack/pack) && - pack=".git/objects/pack/pack-${pack}" + pack=".git/objects/pack/pack-${pack}" && + rm -f .git/objects/pack/pack-corrupt-* } do_corrupt_object() { diff --git a/t/t5310-pack-bitmaps.sh b/t/t5310-pack-bitmaps.sh index 44325741c1e4bd..6cc738410fa248 100755 --- a/t/t5310-pack-bitmaps.sh +++ b/t/t5310-pack-bitmaps.sh @@ -2,6 +2,7 @@ test_description='exercise basic bitmap functionality' +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh . "$TEST_DIRECTORY"/lib-bitmap.sh diff --git a/t/t5326-multi-pack-bitmaps.sh b/t/t5326-multi-pack-bitmaps.sh index 832b92619c06b1..6eaa692f33b5c4 100755 --- a/t/t5326-multi-pack-bitmaps.sh +++ b/t/t5326-multi-pack-bitmaps.sh @@ -1,6 +1,8 @@ #!/bin/sh test_description='exercise basic multi-pack bitmap functionality' + +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh . "${TEST_DIRECTORY}/lib-bitmap.sh" diff --git a/t/t5329-pack-objects-cruft.sh b/t/t5329-pack-objects-cruft.sh index fc5fedbe9b0c4d..445739d06c98d0 100755 --- a/t/t5329-pack-objects-cruft.sh +++ b/t/t5329-pack-objects-cruft.sh @@ -1,6 +1,8 @@ #!/bin/sh test_description='cruft pack related pack-objects tests' + +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh objdir=.git/objects diff --git a/t/t5500-fetch-pack.sh b/t/t5500-fetch-pack.sh index 585ea0ee168319..605f17240c191a 100755 --- a/t/t5500-fetch-pack.sh +++ b/t/t5500-fetch-pack.sh @@ -8,6 +8,7 @@ test_description='Testing multi_ack pack fetching' GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh # Test fetch-pack/upload-pack pair. diff --git a/t/t5539-fetch-http-shallow.sh b/t/t5539-fetch-http-shallow.sh index 3ea75d34ca0e7a..82fe09d0a97554 100755 --- a/t/t5539-fetch-http-shallow.sh +++ b/t/t5539-fetch-http-shallow.sh @@ -5,6 +5,7 @@ test_description='fetch/clone from a shallow clone over http' GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh . "$TEST_DIRECTORY"/lib-httpd.sh start_httpd diff --git a/t/t5540-http-push-webdav.sh b/t/t5540-http-push-webdav.sh index 37db3dec0c5b39..27389b09081fbe 100755 --- a/t/t5540-http-push-webdav.sh +++ b/t/t5540-http-push-webdav.sh @@ -10,6 +10,7 @@ This test runs various sanity checks on http-push.' GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh if git http-push > /dev/null 2>&1 || [ $? -eq 128 ] diff --git a/t/t5541-http-push-smart.sh b/t/t5541-http-push-smart.sh index 71428f3d5c760a..3ad514bbd4e303 100755 --- a/t/t5541-http-push-smart.sh +++ b/t/t5541-http-push-smart.sh @@ -7,6 +7,7 @@ test_description='test smart pushing over http via http-backend' GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh ROOT_PATH="$PWD" diff --git a/t/t5542-push-http-shallow.sh b/t/t5542-push-http-shallow.sh index c2cc83182f9a6b..07624a1d7f6a8d 100755 --- a/t/t5542-push-http-shallow.sh +++ b/t/t5542-push-http-shallow.sh @@ -5,6 +5,7 @@ test_description='push from/to a shallow clone over http' GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh . "$TEST_DIRECTORY"/lib-httpd.sh start_httpd diff --git a/t/t5550-http-fetch-dumb.sh b/t/t5550-http-fetch-dumb.sh index ea8e48f627315f..58189c9f7dc9bd 100755 --- a/t/t5550-http-fetch-dumb.sh +++ b/t/t5550-http-fetch-dumb.sh @@ -4,6 +4,7 @@ test_description='test dumb fetching over http via static file' GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh if test_have_prereq !REFFILES diff --git a/t/t5551-http-fetch-smart.sh b/t/t5551-http-fetch-smart.sh index 85fd0a197d0356..03662b9ade8fab 100755 --- a/t/t5551-http-fetch-smart.sh +++ b/t/t5551-http-fetch-smart.sh @@ -5,6 +5,7 @@ test_description="test smart fetching over http via http-backend ($HTTP_PROTO)" GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh . "$TEST_DIRECTORY"/lib-httpd.sh test "$HTTP_PROTO" = "HTTP/2" && enable_http2 @@ -186,6 +187,28 @@ test_expect_success 'clone from password-protected repository' ' test_cmp expect actual ' +test_expect_success 'credential.interactive=false skips askpass' ' + set_askpass bogus nonsense && + ( + GIT_TRACE2_EVENT="$(pwd)/interactive-true" && + export GIT_TRACE2_EVENT && + test_must_fail git clone --bare "$HTTPD_URL/auth/smart/repo.git" interactive-true-dir && + test_region credential interactive interactive-true && + + GIT_TRACE2_EVENT="$(pwd)/interactive-false" && + export GIT_TRACE2_EVENT && + test_must_fail git -c credential.interactive=false \ + clone --bare "$HTTPD_URL/auth/smart/repo.git" interactive-false-dir && + test_region ! credential interactive interactive-false && + + GIT_TRACE2_EVENT="$(pwd)/interactive-never" && + export GIT_TRACE2_EVENT && + test_must_fail git -c credential.interactive=never \ + clone --bare "$HTTPD_URL/auth/smart/repo.git" interactive-never-dir && + test_region ! credential interactive interactive-never + ) +' + test_expect_success 'clone from auth-only-for-push repository' ' echo two >expect && set_askpass wrong && diff --git a/t/t5582-fetch-negative-refspec.sh b/t/t5582-fetch-negative-refspec.sh index 7a80e47c2b70a8..7fa54a4029ad44 100755 --- a/t/t5582-fetch-negative-refspec.sh +++ b/t/t5582-fetch-negative-refspec.sh @@ -8,6 +8,7 @@ test_description='"git fetch" with negative refspecs. GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success setup ' diff --git a/t/t5619-clone-local-ambiguous-transport.sh b/t/t5619-clone-local-ambiguous-transport.sh index cce62bf78d3351..1d4efe414daac1 100755 --- a/t/t5619-clone-local-ambiguous-transport.sh +++ b/t/t5619-clone-local-ambiguous-transport.sh @@ -2,6 +2,7 @@ test_description='test local clone with ambiguous transport' +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh . "$TEST_DIRECTORY/lib-httpd.sh" diff --git a/t/t5700-protocol-v1.sh b/t/t5700-protocol-v1.sh index a73b4d4ff6a0d2..985e04d06e0e7c 100755 --- a/t/t5700-protocol-v1.sh +++ b/t/t5700-protocol-v1.sh @@ -11,6 +11,7 @@ export GIT_TEST_PROTOCOL_VERSION GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh # Test protocol v1 with 'git://' transport diff --git a/t/t6004-rev-list-path-optim.sh b/t/t6004-rev-list-path-optim.sh index cd4f420e2a1e39..5416241edea0a0 100755 --- a/t/t6004-rev-list-path-optim.sh +++ b/t/t6004-rev-list-path-optim.sh @@ -16,6 +16,7 @@ test_description='git rev-list trivial path optimization test GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success setup ' diff --git a/t/t6019-rev-list-ancestry-path.sh b/t/t6019-rev-list-ancestry-path.sh index 738da23628b12b..1aabab69568a18 100755 --- a/t/t6019-rev-list-ancestry-path.sh +++ b/t/t6019-rev-list-ancestry-path.sh @@ -29,6 +29,7 @@ test_description='--ancestry-path' GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_merge () { diff --git a/t/t6111-rev-list-treesame.sh b/t/t6111-rev-list-treesame.sh index 90ff14164009d0..f63bc8d3da62af 100755 --- a/t/t6111-rev-list-treesame.sh +++ b/t/t6111-rev-list-treesame.sh @@ -16,6 +16,7 @@ test_description='TREESAME and limiting' GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh note () { diff --git a/t/t7061-wtstatus-ignore.sh b/t/t7061-wtstatus-ignore.sh index 2f9bea9793cec8..64145a05b1fd4e 100755 --- a/t/t7061-wtstatus-ignore.sh +++ b/t/t7061-wtstatus-ignore.sh @@ -2,6 +2,7 @@ test_description='git-status ignored files' +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh cat >expected <<\EOF diff --git a/t/t7406-submodule-update.sh b/t/t7406-submodule-update.sh index 15e29f538cacc1..78c318a275bca7 100755 --- a/t/t7406-submodule-update.sh +++ b/t/t7406-submodule-update.sh @@ -12,6 +12,7 @@ submodule and "git submodule update --rebase/--merge" does not detach the HEAD. GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh # This test script contains test cases that need to create symbolic links. To diff --git a/t/t7407-submodule-foreach.sh b/t/t7407-submodule-foreach.sh index 8d7b234beb8b09..9f688932613598 100755 --- a/t/t7407-submodule-foreach.sh +++ b/t/t7407-submodule-foreach.sh @@ -12,6 +12,7 @@ that are currently checked out. GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh diff --git a/t/t7408-submodule-reference.sh b/t/t7408-submodule-reference.sh index d6040e0a337033..7e1afa9ce470b1 100755 --- a/t/t7408-submodule-reference.sh +++ b/t/t7408-submodule-reference.sh @@ -4,6 +4,8 @@ # test_description='test clone --reference' + +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh base_dir=$(pwd) diff --git a/t/t7411-submodule-config.sh b/t/t7411-submodule-config.sh index 31271f8e0a61f7..af0de496e07470 100755 --- a/t/t7411-submodule-config.sh +++ b/t/t7411-submodule-config.sh @@ -10,6 +10,7 @@ from the database and from the worktree works. ' TEST_NO_CREATE_REPO=1 +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success 'setup' ' diff --git a/t/t7420-submodule-set-url.sh b/t/t7420-submodule-set-url.sh index bf7f15ee797395..d7fe910bbe1fe6 100755 --- a/t/t7420-submodule-set-url.sh +++ b/t/t7420-submodule-set-url.sh @@ -10,6 +10,7 @@ as expected. ' TEST_NO_CREATE_REPO=1 +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success 'setup' ' diff --git a/t/t7422-submodule-output.sh b/t/t7422-submodule-output.sh index ab946ec9405deb..c1686d6bb5f6f0 100755 --- a/t/t7422-submodule-output.sh +++ b/t/t7422-submodule-output.sh @@ -167,4 +167,11 @@ do ' done +test_expect_success !MINGW 'git submodule status --recursive propagates SIGPIPE' ' + { git submodule status --recursive 2>err; echo $?>status; } | + grep -q X/S && + test_must_be_empty err && + test_match_signal 13 "$(cat status)" +' + test_done diff --git a/t/t7521-ignored-mode.sh b/t/t7521-ignored-mode.sh index a88b02b06ed342..edce10f998eecb 100755 --- a/t/t7521-ignored-mode.sh +++ b/t/t7521-ignored-mode.sh @@ -2,6 +2,7 @@ test_description='git status ignored modes' +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success 'setup initial commit and ignore file' ' diff --git a/t/t7524-commit-summary.sh b/t/t7524-commit-summary.sh index 47b2f1dc22a5cb..a8fceb6a47c348 100755 --- a/t/t7524-commit-summary.sh +++ b/t/t7524-commit-summary.sh @@ -1,6 +1,8 @@ #!/bin/sh test_description='git commit summary' + +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success 'setup' ' diff --git a/t/t7601-merge-pull-config.sh b/t/t7601-merge-pull-config.sh index a94387a75f2f48..7fd8c086af3f16 100755 --- a/t/t7601-merge-pull-config.sh +++ b/t/t7601-merge-pull-config.sh @@ -4,6 +4,7 @@ test_description='git merge Testing pull.* configuration parsing and other things.' +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success 'setup' ' diff --git a/t/t7700-repack.sh b/t/t7700-repack.sh index 1feb6643e69979..fc2cc9d37be76d 100755 --- a/t/t7700-repack.sh +++ b/t/t7700-repack.sh @@ -2,6 +2,7 @@ test_description='git repack works correctly' +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh . "${TEST_DIRECTORY}/lib-bitmap.sh" . "${TEST_DIRECTORY}/lib-midx.sh" diff --git a/t/t7800-difftool.sh b/t/t7800-difftool.sh index cc917b257e3bb8..f67b9345b8a013 100755 --- a/t/t7800-difftool.sh +++ b/t/t7800-difftool.sh @@ -11,6 +11,7 @@ Testing basic diff tool invocation GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh difftool_test_setup () diff --git a/t/t7814-grep-recurse-submodules.sh b/t/t7814-grep-recurse-submodules.sh index 167fe661504a2b..55ed630e77ed0d 100755 --- a/t/t7814-grep-recurse-submodules.sh +++ b/t/t7814-grep-recurse-submodules.sh @@ -7,6 +7,7 @@ submodules. ' TEST_CREATE_REPO_NO_TEMPLATE=1 +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh GIT_TEST_FATAL_REGISTER_SUBMODULE_ODB=1 diff --git a/t/t7900-maintenance.sh b/t/t7900-maintenance.sh index abae7a97546f66..a66d0e089d2d3a 100755 --- a/t/t7900-maintenance.sh +++ b/t/t7900-maintenance.sh @@ -2,6 +2,7 @@ test_description='git maintenance builtin' +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh GIT_TEST_COMMIT_GRAPH=0 @@ -825,6 +826,9 @@ test_expect_success 'start and stop Linux/systemd maintenance' ' test_systemd_analyze_verify "systemd/user/git-maintenance@daily.service" && test_systemd_analyze_verify "systemd/user/git-maintenance@weekly.service" && + grep "core.askPass=true" "systemd/user/git-maintenance@.service" && + grep "credential.interactive=false" "systemd/user/git-maintenance@.service" && + printf -- "--user enable --now git-maintenance@%s.timer\n" hourly daily weekly >expect && test_cmp expect args && diff --git a/t/t9210-scalar.sh b/t/t9210-scalar.sh index e8613990e13705..027235d61aa35e 100755 --- a/t/t9210-scalar.sh +++ b/t/t9210-scalar.sh @@ -194,8 +194,11 @@ test_expect_success 'scalar reconfigure' ' scalar reconfigure one && test true = "$(git -C one/src config core.preloadIndex)" && git -C one/src config core.preloadIndex false && - scalar reconfigure -a && - test true = "$(git -C one/src config core.preloadIndex)" + rm one/src/cron.txt && + GIT_TRACE2_EVENT="$(pwd)/reconfigure" scalar reconfigure -a && + test_path_is_file one/src/cron.txt && + test true = "$(git -C one/src config core.preloadIndex)" && + test_subcommand git maintenance start opts.disable_auto_compact = i != n; - err = reftable_stack_new_addition(&add, st); + err = reftable_stack_new_addition(&add, st, 0); check(!err); err = reftable_addition_add(add, write_test_ref, &ref); @@ -1313,6 +1375,7 @@ int cmd_main(int argc UNUSED, const char *argv[] UNUSED) TEST(t_reftable_stack_reload_with_missing_table(), "stack iteration with garbage tables"); TEST(t_reftable_stack_tombstone(), "'tombstone' refs in stack"); TEST(t_reftable_stack_transaction_api(), "update transaction to stack"); + TEST(t_reftable_stack_transaction_with_reload(), "transaction with reload"); TEST(t_reftable_stack_transaction_api_performs_auto_compaction(), "update transaction triggers auto-compaction"); TEST(t_reftable_stack_update_index_check(), "update transactions with equal update indices"); TEST(t_reftable_stack_uptodate(), "stack must be reloaded before ref update"); diff --git a/tmp-objdir.c b/tmp-objdir.c index c2fb9f91930a30..9da0071cba8375 100644 --- a/tmp-objdir.c +++ b/tmp-objdir.c @@ -206,9 +206,11 @@ static int read_dir_paths(struct string_list *out, const char *path) return 0; } -static int migrate_paths(struct strbuf *src, struct strbuf *dst); +static int migrate_paths(struct strbuf *src, struct strbuf *dst, + enum finalize_object_file_flags flags); -static int migrate_one(struct strbuf *src, struct strbuf *dst) +static int migrate_one(struct strbuf *src, struct strbuf *dst, + enum finalize_object_file_flags flags) { struct stat st; @@ -220,12 +222,18 @@ static int migrate_one(struct strbuf *src, struct strbuf *dst) return -1; } else if (errno != EEXIST) return -1; - return migrate_paths(src, dst); + return migrate_paths(src, dst, flags); } - return finalize_object_file(src->buf, dst->buf); + return finalize_object_file_flags(src->buf, dst->buf, flags); } -static int migrate_paths(struct strbuf *src, struct strbuf *dst) +static int is_loose_object_shard(const char *name) +{ + return strlen(name) == 2 && isxdigit(name[0]) && isxdigit(name[1]); +} + +static int migrate_paths(struct strbuf *src, struct strbuf *dst, + enum finalize_object_file_flags flags) { size_t src_len = src->len, dst_len = dst->len; struct string_list paths = STRING_LIST_INIT_DUP; @@ -239,11 +247,15 @@ static int migrate_paths(struct strbuf *src, struct strbuf *dst) for (i = 0; i < paths.nr; i++) { const char *name = paths.items[i].string; + enum finalize_object_file_flags flags_copy = flags; strbuf_addf(src, "/%s", name); strbuf_addf(dst, "/%s", name); - ret |= migrate_one(src, dst); + if (is_loose_object_shard(name)) + flags_copy |= FOF_SKIP_COLLISION_CHECK; + + ret |= migrate_one(src, dst, flags_copy); strbuf_setlen(src, src_len); strbuf_setlen(dst, dst_len); @@ -271,7 +283,7 @@ int tmp_objdir_migrate(struct tmp_objdir *t) strbuf_addbuf(&src, &t->path); strbuf_addstr(&dst, repo_get_object_directory(the_repository)); - ret = migrate_paths(&src, &dst); + ret = migrate_paths(&src, &dst, 0); strbuf_release(&src); strbuf_release(&dst); diff --git a/trace2/tr2_tls.c b/trace2/tr2_tls.c index 4f75392952b6a4..7b023c1bfc65fa 100644 --- a/trace2/tr2_tls.c +++ b/trace2/tr2_tls.c @@ -152,11 +152,19 @@ uint64_t tr2tls_absolute_elapsed(uint64_t us) return us - tr2tls_us_start_process; } +static void tr2tls_key_destructor(void *payload) +{ + struct tr2tls_thread_ctx *ctx = payload; + free((char *)ctx->thread_name); + free(ctx->array_us_start); + free(ctx); +} + void tr2tls_init(void) { tr2tls_start_process_clock(); - pthread_key_create(&tr2tls_key, NULL); + pthread_key_create(&tr2tls_key, tr2tls_key_destructor); init_recursive_mutex(&tr2tls_mutex); tr2tls_thread_main = diff --git a/transport-helper.c b/transport-helper.c index 03069be30d34c0..27185a3c20e23f 100644 --- a/transport-helper.c +++ b/transport-helper.c @@ -742,8 +742,14 @@ static int fetch_refs(struct transport *transport, return -1; } - if (!data->get_refs_list_called) - get_refs_list_using_list(transport, 0); + if (!data->get_refs_list_called) { + /* + * We do not care about the list of refs returned, but only + * that the "list" command was sent. + */ + struct ref *dummy = get_refs_list_using_list(transport, 0); + free_refs(dummy); + } count = 0; for (i = 0; i < nr_heads; i++) @@ -1048,6 +1054,7 @@ static int push_refs_with_push(struct transport *transport, if (atomic) { reject_atomic_push(remote_refs, mirror); string_list_clear(&cas_options, 0); + strbuf_release(&buf); return 0; } else continue; diff --git a/transport.c b/transport.c index 3c4714581f58eb..1098bbd60e4f65 100644 --- a/transport.c +++ b/transport.c @@ -414,7 +414,7 @@ static int fetch_refs_via_pack(struct transport *transport, struct git_transport_data *data = transport->data; struct ref *refs = NULL; struct fetch_pack_args args; - struct ref *refs_tmp = NULL; + struct ref *refs_tmp = NULL, **to_fetch_dup = NULL; memset(&args, 0, sizeof(args)); args.uploadpack = data->options.uploadpack; @@ -477,6 +477,14 @@ static int fetch_refs_via_pack(struct transport *transport, goto cleanup; } + /* + * Create a shallow copy of `sought` so that we can free all of its entries. + * This is because `fetch_pack()` will modify the array to evict some + * entries, but won't free those. + */ + DUP_ARRAY(to_fetch_dup, to_fetch, nr_heads); + to_fetch = to_fetch_dup; + refs = fetch_pack(&args, data->fd, refs_tmp ? refs_tmp : transport->remote_refs, to_fetch, nr_heads, &data->shallow, @@ -500,6 +508,7 @@ static int fetch_refs_via_pack(struct transport *transport, ret = -1; data->conn = NULL; + free(to_fetch_dup); free_refs(refs_tmp); free_refs(refs); list_objects_filter_release(&args.filter_options);